ccutil/memblk.cpp

Go to the documentation of this file.
00001 
00020 #include          "mfcpch.h"     //precompiled headers
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;         //frame size
00042     unsigned cursp;              //stack
00043     unsigned currls;             //pc space
00044     unsigned currlo;             //pc offset
00045     unsigned curdp;              //data pointer
00046     unsigned toprp;              //rp
00047     unsigned topmrp;             //mrp
00048     unsigned topsr0;             //sr0
00049     unsigned topsr4;             //sr4
00050     unsigned r3;                 //gr3
00051     unsigned cur_r19;            //gr19
00052 };
00053 
00054 MEMUNION *free_block = NULL;     //head of freelist
00055 
00056 #define EXTERN
00057 
00058 EXTERN MEM_ALLOCATOR big_mem;
00059 EXTERN MEM_ALLOCATOR main_mem;
00060                                  //heads of freelists
00061 EXTERN MEMUNION *free_structs[MAX_STRUCTS];
00062                                  //number issued
00063 EXTERN INT32 structs_in_use[MAX_STRUCTS];
00064                                  //number issued
00065 EXTERN INT32 blocks_in_use[MAX_STRUCTS];
00066                                  //head of block lists
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                                  //no of names
00071 EXTERN INT16 name_counts[MAX_STRUCTS];
00072 EXTERN INT32 free_struct_blocks; //no of free 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 (            //initialize
00089 void *(*ext_malloc) (INT32),     //external source
00090 void (*ext_free) (void *),       //external free
00091 INT32 firstsize,                 //size of first block
00092 INT32 lastsize,                  //size of last block
00093 INT32 maxchunk                   //biggest request
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(            //get hash code
00118                                   void *addr  //return address
00119                                  ) {
00120   INT32 index;                   //index to table
00121   INT32 initial_hash;            //initial index
00122 
00123   if (callers == NULL)
00124     init_callers();  //setup table
00125                                  //get hash code
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                                  //setup free table
00146       callers[index].init_freeers ();
00147   }
00148   return (UINT16) index;
00149 }
00150 
00151 
00157 void MALLOC_CALL::count_freeer(            //count calls to free
00158                                void *addr  //return address
00159                               ) {
00160   INT32 entries;                 //entries in table
00161   INT32 index;                   //index to table
00162   INT32 initial_hash;            //initial index
00163 
00164   if (free_list == NULL)
00165     init_freeers();  //setup table
00166   entries = 1 << free_bits;
00167                                  //get hash code
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++;      //count them
00187 }
00188 
00189 
00193 void MEM_ALLOCATOR::init_callers() {  //setup hash table
00194   INT32 depth = mem_mallocdepth;
00195 
00196   mem_mallocdepth.set_value (0); //can't register it
00197   call_bits = mem_mallocbits;
00198   entries = 1 << call_bits;
00199                                  //make an array
00200   callers = new MALLOC_CALL[entries];
00201   mem_mallocdepth.set_value (depth);
00202 }
00203 
00204 
00208 void MALLOC_CALL::init_freeers() {  //setup hash table
00209   INT32 entries;                 //entries in table
00210   INT32 depth = mem_mallocdepth;
00211 
00212   mem_mallocdepth.set_value (0); //can't register it
00213   free_bits = mem_freebits;
00214   entries = 1 << free_bits;
00215                                  //make an array
00216   free_list = new FREE_CALL[entries];
00217   mem_mallocdepth.set_value (depth);
00218 }
00219 
00220 
00224 void MEM_ALLOCATOR::reduce_counts() {  //divide by 2
00225   MEMBLOCK *block;               //current block
00226   MEMUNION *chunk;               //current chunk
00227   INT32 chunksize;               //size of chunk
00228   INT32 blockindex;              //index of block
00229 
00230   check_mem ("Reducing counts", JUSTCHECKS);
00231   for (blockindex = 0; blockindex < blockcount; blockindex++) {
00232                                  //current block
00233     block = &memblocks[blockindex];
00234                                  //scan all chunks
00235     for (chunk = block->blockstart; chunk != block->blockend; chunk += chunksize) {
00236       chunksize = chunk->size;   //size of chunk
00237       if (chunksize < 0)
00238         chunksize = -chunksize;  //absolute size
00239       chunk->age /= 2;           //divide ages
00240     }
00241   }
00242 }
00243 
00244 
00248 void MEM_ALLOCATOR::display_counts() {  //count up
00249   MEMBLOCK *block;               //current block
00250   MEMUNION *chunk;               //current chunk
00251   INT32 chunksize;               //size of chunk
00252   INT32 blockindex;              //index of block
00253   INT32 buckets;                 //required buckets
00254   INT32 bucketsize;              //no in each bucket
00255   INT32 callindex;               //index to callers
00256   INT32 freeindex;               //index to freeers
00257   INT32 freeentries;             //table size
00258   INT32 totalchunks;             //total chunk counts
00259   INT32 totalspace;              //total mem space
00260   INT32 totalpchunks;            //permanent chunks
00261   INT32 totalpspace;             //permanent space
00262   INT32 totalfrees;              //total free calls
00263 
00264   if (callers == NULL)
00265     return;                      //can't do anything
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                                  //current block
00281     block = &memblocks[blockindex];
00282                                  //scan all chunks
00283     for (chunk = block->blockstart; chunk != block->topchunk; chunk += chunksize) {
00284       chunksize = chunk->size;   //size of chunk
00285       if (chunksize < 0) {
00286         chunksize = -chunksize;  //absolute size
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                                  //scan all chunks
00296     for (; chunk != block->blockend; chunk += chunksize) {
00297       chunksize = chunk->size;   //size of chunk
00298       if (chunksize < 0) {
00299         chunksize = -chunksize;  //absolute size
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(                     //check consistency
00372                           const char *string,  //context message
00373                           INT8 level           //level of check
00374                          ) {
00375   MEMBLOCK *block;               //current block
00376   MEMUNION *chunk;               //current chunk
00377   MEMUNION *prevchunk;           //previous chunk
00378   INT32 chunksize;               //size of chunk
00379   INT32 usedcount;               //no of used chunks
00380   INT32 usedsize;                //size of used chunks
00381   INT32 freecount;               //no of free chunks
00382   INT32 freesize;                //size of free chunks
00383   INT32 biggest;                 //biggest free chunk
00384   INT32 totusedcount;            //no of used chunks
00385   INT32 totusedsize;             //size of used chunks
00386   INT32 totfreecount;            //no of free chunks
00387   INT32 totfreesize;             //size of free chunks
00388   INT32 totbiggest;              //biggest free chunk
00389   INT32 totblocksize;            //total size of blocks
00390   INT32 chunkindex;              //index of chunk
00391   INT32 blockindex;              //index of block
00392 
00393   if (level >= MEMCHECKS)
00394     tprintf ("\nMEM_ALLOCATOR::check:at '%s'\n", string);
00395   totusedcount = 0;              //grand totals
00396   totusedsize = 0;
00397   totfreecount = 0;
00398   totfreesize = 0;
00399   totbiggest = 0;
00400   totblocksize = 0;
00401   for (blockindex = 0; blockindex < blockcount; blockindex++) {
00402                                  //current block
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;    //zero counters
00410     freecount = freesize = 0;    //zero counters
00411     biggest = 0;
00412                                  //scan all chunks
00413     for (chunkindex = 0, prevchunk = NULL, chunk = block->blockstart; chunk != block->blockend; chunkindex++, chunk += chunksize) {
00414       chunksize = chunk->size;   //size of chunk
00415       if (chunksize < 0)
00416         chunksize = -chunksize;  //absolute size
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                                  //illegal sizes
00425       if (chunksize == 0 || chunk->size == -1
00426                                  //out of bounds
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++;             //used block
00435         usedsize += chunksize;
00436       }
00437       else {
00438         freecount++;             //free block
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;   //grand totals
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(              //permanent space
00486                              INT32 count,  //block size to allocate
00487                              void *caller  //ptr to caller
00488                             ) {
00489   MEMBLOCK *block;               //current block
00490   MEMUNION *chunk;               //current chunk
00491 
00492   if (count < 1 || count > biggestblock)
00493                                  //request too big
00494     MEMTOOBIG.error ("alloc_mem_p", ABORT, "%d", (int) count);
00495 
00496   count += sizeof (MEMUNION) - 1;//round up to word
00497   count /= sizeof (MEMUNION);
00498   count++;                       //and add one
00499   if (topblock == NULL) {
00500     topblock = new_block (count);//get first block
00501     currblock = topblock;
00502     if (topblock == NULL) {
00503       check_mem ("alloc_mem_p returning NULL", MEMCHECKS);
00504       return NULL;
00505     }
00506   }
00507   block = topblock;              //current block
00508   do {
00509     chunk = block->topchunk;
00510     if (chunk->size < count)
00511       block = block->next;       //try next block
00512   }
00513                                  //until all tried
00514   while (chunk->size < count && block != topblock);
00515   if (chunk->size < count) {     //still no good
00516     chunk = (MEMUNION *) alloc ((count - 1) * sizeof (MEMUNION), caller);
00517     //try last resort
00518     if (chunk != NULL)
00519       return chunk;
00520     check_mem ("alloc_mem_p returning NULL", MEMCHECKS);
00521     return NULL;
00522   }
00523   block->upperspace -= count;    //less above freechunk
00524   if (chunk->size > count) {
00525     chunk->size -= count;
00526     chunk += chunk->size;
00527   }
00528   chunk->size = -count;          //mark as in use
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;              //created chunk
00537 }
00538 
00539 
00543 void *MEM_ALLOCATOR::alloc(              //get memory
00544                            INT32 count,  //no of bytes to get
00545                            void *caller  //ptr to caller
00546                           ) {
00547   MEMBLOCK *block;               //current block
00548   MEMUNION *chunk;               //current chunk
00549   INT32 chunksize;               //size of free chunk
00550   MEMUNION *chunkstart;          //start of free chunk
00551 
00552   if (count < 1 || count > biggestblock)
00553     MEMTOOBIG.error ("alloc_mem", ABORT, "%d", (int) count);
00554   //request too big
00555 
00556   count += sizeof (MEMUNION) - 1;//round up to word
00557   count /= sizeof (MEMUNION);
00558   count++;                       //and add one
00559   if (currblock == NULL) {
00560                                  //get first block
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;             //current block
00569   if (block->upperspace <= block->lowerspace) {
00570                                  //restart chunklist
00571     block->freechunk = block->blockstart;
00572     block->upperspace += block->lowerspace;
00573     block->lowerspace = 0;       //correct space counts
00574   }
00575   chunk = block->freechunk;      //current free chunk
00576   if (chunk->size < count) {     //big enough?
00577     do {
00578                                  //search for free chunk
00579       chunk = block->find_chunk (count);
00580       if (chunk->size < count)
00581         block = block->next;     //try next block
00582     }
00583                                  //until all tried
00584     while (chunk->size < count && block != currblock);
00585     if (chunk->size < count) {   //still no good
00586                                  //get a new block
00587       currblock = new_block (count);
00588       topblock = currblock;      //set perms here too
00589       if (currblock == NULL) {
00590         check_mem ("alloc_mem returning NULL", MEMCHECKS);
00591         return NULL;
00592       }
00593       block = currblock;
00594       chunk = block->freechunk;  //bound to be big enough
00595     }
00596   }
00597   chunkstart = chunk;            //start of chunk
00598   if (chunk == block->topchunk && chunk + count != block->blockend)
00599     block->topchunk += count;    //top has moved
00600   block->upperspace -= count;    //upper part used
00601   chunksize = chunk->size;       //size of free chunk
00602   chunk->size = -count;          //mark as used
00603   chunk += count;                //next free space
00604   totalmem -= count;             //no of free elements
00605   if (chunksize > count)         //bigger than exact?
00606                                  //remaining space
00607     chunk->size = chunksize - count;
00608   else if (chunk == block->blockend) {
00609     chunk = block->blockstart;   //restart block
00610     block->upperspace = block->lowerspace;
00611     block->lowerspace = 0;       //fix space counts
00612   }
00613   block->freechunk = chunk;      //next free block
00614   if (mem_mallocdepth > 0) {
00615     set_owner(chunkstart, caller);
00616   }
00617   else {
00618     chunkstart->owner = 0;
00619     chunkstart->age = 0;
00620   }
00621   chunkstart++;                  //start of block
00622   return chunkstart;             //pointer to block
00623 }
00624 
00625 
00629 void MEM_ALLOCATOR::set_owner(                       //get memory
00630                               MEMUNION *chunkstart,  //chunk to set
00631                               void *caller           //ptr to caller
00632                              ) {
00633   UINT16 callindex;              //hash code
00634 
00635   callindex = hash_caller (caller);
00636   chunkstart->owner = callindex;
00637                                  //store evidence
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++;             //count calls
00643     if (malloc_serial == 0) {
00644                                  //wrap around
00645       reduce_counts();  //fix serial numbers
00646       malloc_serial = MAX_INT16 + 1;
00647                                  //all worth double
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(                 //free memory
00666                             void *oldchunk,  //chunk to free
00667                             void *caller     //ptr to caller
00668                            ) {
00669   MEMUNION *chunk;               //current chunk
00670   MEMBLOCK *block;               //current block
00671 
00672   if (oldchunk == NULL)
00673     FREENULLPTR.error ("free_mem", ABORT, NULL);
00674   chunk = (MEMUNION *) oldchunk;
00675   block = currblock;             //current block
00676   if (block == NULL)
00677     NOTMALLOCMEM.error ("free_mem", ABORT, NULL);
00678   do {
00679     block = block->next;
00680   }
00681                                  //outside the block
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                                  //in no block
00687     NOTMALLOCMEM.error ("free_mem", ABORT, NULL);
00688 
00689   chunk--;                       //point to size
00690   if (chunk->size == 0)
00691                                  //zero size
00692     FREEILLEGALPTR.error ("free_mem", ABORT, NULL);
00693   else if (chunk->size > 0)
00694                                  //already free
00695     FREEFREEDBLOCK.error ("free_mem", ABORT, NULL);
00696   chunk->size = -chunk->size;    //mark it free
00697   if (mem_freedepth > 0 && callers != NULL) {
00698                                  //count calls
00699     callers[chunk->owner].count_freeer (caller);
00700   }
00701   totalmem += chunk->size;       //total free memory
00702   if (chunk - block->freechunk < 0)
00703                                  //extra below
00704     block->lowerspace += chunk->size;
00705   else
00706                                  //extra above
00707     block->upperspace += chunk->size;
00708 }
00709 
00710 
00714 MEMBLOCK *MEM_ALLOCATOR::new_block(               //get new big block
00715                                    INT32 minsize  //minimum size
00716                                   ) {
00717   MEMBLOCK *newblock;            //new block
00718 
00719   if (blockcount >= MAXBLOCKS) {
00720                                  //can't have another
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                                  //get a new one
00733   newblock = &memblocks[blockcount++];
00734   while (memsize < minsize)
00735     memsize *= 4;                //go up in sizes
00736                                  //get a big block
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);  //hangup for js
00744     #endif
00745     return NULL;
00746   }
00747                                  //end of block
00748   newblock->blockend = newblock->blockstart + memsize;
00749                                  //first free chunk
00750   newblock->freechunk = newblock->blockstart;
00751   newblock->topchunk = newblock->blockstart;
00752   newblock->lowerspace = 0;
00753   newblock->upperspace = memsize;//amount available
00754                                  //set pointer
00755   newblock->freechunk->size = memsize;
00756   newblock->freechunk->owner = 0;
00757   newblock->freechunk->age = 0;
00758 
00759   totalmem += memsize;           //total assigned mem
00760 
00761   if (memsize < maxsize)
00762     memsize *= 4;                //successively bigger
00763   if (currblock == NULL) {
00764     newblock->next = newblock;   //first block
00765   }
00766   else {
00767                                  //insert in list
00768     newblock->next = currblock->next;
00769     currblock->next = newblock;
00770   }
00771   return newblock;               //new block
00772 }
00773 
00774 
00778 MEMUNION *MEMBLOCK::find_chunk(             //find free chunk
00779                                INT32 count  //size required
00780                               ) {
00781   MEMUNION *chunk;               //current chunk
00782   INT32 chunksize;               //size of free chunk
00783   MEMUNION *chunkstart;          //start of free chunk
00784   INT32 spaceshift;              //shift in lowerspace
00785 
00786   if (upperspace <= lowerspace) {
00787     freechunk = blockstart;      //restart chunklist
00788     upperspace += lowerspace;
00789     lowerspace = 0;              //correct space counts
00790   }
00791   chunk = freechunk;             //current free chunk
00792   if (chunk->size < count) {     //big enough?
00793     spaceshift = 0;
00794     do {
00795       while (chunk->size < 0) {  //find free chunk
00796         chunk -= chunk->size;    //skip forward
00797         if (chunk == blockend) {
00798           chunk = blockstart;    //restart block
00799                                  //gone back to start
00800           spaceshift = -lowerspace;
00801         }
00802         if (chunk == freechunk)
00803           return chunk;          //gone all round & failed
00804       }
00805       chunkstart = chunk;        //start of chunk
00806       chunksize = chunk->size;;
00807       chunk += chunk->size;
00808       while (chunk != blockend   //until end
00809       && chunk->size > 0) {      //or used
00810         chunksize += chunk->size;//coalesce free blocks
00811                                  //gone all round
00812         if (chunk == freechunk) {
00813                                  //ensure it is at end
00814           freechunk += chunk->size;
00815           upperspace -= chunk->size;
00816           lowerspace += chunk->size;
00817           spaceshift -= chunk->size;
00818         }
00819         if (chunk == topchunk)   //got back to end one
00820           topchunk = chunkstart; //end one bigger
00821         chunk += chunk->size;    //get next block
00822       }
00823                                  //new big block
00824       chunkstart->size = chunksize;
00825       if (chunksize < count)
00826         spaceshift += chunksize; //skipping free block
00827       if (chunk == blockend) {
00828         chunk = blockstart;      //back to start
00829         if (freechunk == blockend) {
00830           freechunk = blockstart;//so is freechunk
00831           upperspace += lowerspace;
00832           lowerspace = 0;
00833           spaceshift = 0;
00834         }
00835         else
00836                                  //so is shift
00837             spaceshift = -lowerspace;
00838       }
00839     }
00840     while (chunksize < count && chunk != freechunk);
00841     if (chunksize < count)
00842       return chunk;              //failed
00843     lowerspace += spaceshift;    //get space counts right
00844     upperspace -= spaceshift;
00845     freechunk = chunkstart;
00846     return chunkstart;           //success
00847   }
00848   return chunk;                  //easy
00849 }
00850 
00851 
00852 #ifdef __UNIX__
00853 //#pragma OPTIMIZE OFF        /*force link*/
00854 
00861 void *trace_caller(             //trace stack
00862                    INT32 depth  //depth to trace
00863                   ) {
00864   #ifdef hp9000s800
00865 
00866   unsigned sp, pc, rp;           //registers
00867   UWREC rec1;                    //for unwinder
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;                      //address register
00892 
00893   a6 = &depth - 2;
00894   while (depth > 0) {
00895     a6 = *(void **) a6;          //follow chain
00896     depth--;
00897   }
00898   return *((void **) a6 + 1);
00899   #endif
00900 }
00901 
00902 
00903 //#pragma OPTIMIZE ON
00904 
00905 #else
00906 
00910 void *trace_caller(             //trace stack
00911                    INT32 depth  //depth to trace
00912                   ) {
00913   return NULL;
00914 }
00915 #endif
00916 
00922 INT32 identify_struct_owner(                     //get table index
00923                             INT32 struct_count,  //cell size
00924                             const char *name     //name of type
00925                            ) {
00926   INT32 index;                   //index to structure
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(             //check a structure
00945                   INT8 level,  //print control
00946                   INT32 count  //no of bytes
00947                  ) {
00948   MEMUNION *element;             //current element
00949   MEMUNION *block;               //current block
00950   INT32 struct_count;            //no of required structs
00951   INT32 block_count;             //no of structure blocks
00952   INT32 free_count;              //size of freelist*/
00953   INT32 name_index;              //named holder
00954   INT32 named_total;             //total held by names
00955 
00956                                  //no of MEMUNIONS-1
00957   struct_count = (count - 1) / sizeof (MEMUNION);
00958   if (struct_count < 0 || struct_count >= MAX_STRUCTS)
00959                                  //request too big
00960     MEMTOOBIG.error ("check_struct", ABORT, "%d", (int) count);
00961 
00962   free_count = 0;                //size of freelist
00963                                  //count blocks
00964   for (block_count = 0, block = struct_blocks[struct_count]; block != NULL; block = block->ptr, block_count++);
00965   if (block_count > 0) {
00966                                  //scan freelist
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(            //count in use on structs
01002                    INT8 level  //print control
01003                   ) {
01004   INT8 index;                    //index to structs
01005 
01006   for (index = 1; index <= MAX_STRUCTS; index++)
01007                                  //check number allocated
01008     check_struct (level, index * sizeof (MEMUNION));
01009 }
01010 
01011 
01019 void *new_struct_block() {  //allocate memory
01020   MEMUNION *element;             //current element
01021   MEMUNION *returnelement;       //return value
01022 
01023   returnelement = free_block;
01024   if (returnelement == NULL) {
01025                                  //need a new block
01026     element =
01027       (MEMUNION *) alloc_mem_p (STRUCT_BLOCK_SIZE * sizeof (MEMUNION));
01028     if (element == NULL)
01029       return NULL;               //can't get more
01030     returnelement = element;     //going to return 1st
01031   }
01032   else {
01033                                  //new free one
01034     free_block = returnelement->ptr;
01035   }
01036   return returnelement;          //free cell
01037 }
01038 
01039 
01049 void old_struct_block(                     //free a structure block
01050                       MEMUNION *deadblock  //block to free
01051                      ) {
01052   if (deadblock != NULL) {
01053     deadblock->ptr = free_block; //add to freelist
01054     free_block = deadblock;
01055     free_struct_blocks++;
01056   }
01057   if (free_struct_blocks > MAX_FREE_S_BLOCKS) {
01058     MEMUNION *next_block;        //next in list
01059     deadblock = free_block;
01060     do {
01061       next_block = deadblock->ptr;
01062       free_mem(deadblock);  //really free it
01063       deadblock = next_block;
01064     }
01065     while (deadblock != NULL);
01066     free_struct_blocks = 0;
01067     free_block = NULL;
01068   }
01069 }

Generated on Wed Feb 28 19:49:09 2007 for Tesseract by  doxygen 1.5.1