mux/src/alloc.cpp

Go to the documentation of this file.
00001 // alloc.cpp -- Memory Allocation Subsystem.
00002 //
00003 // $Id: alloc.cpp,v 1.9 2006/01/08 04:26:01 sdennis Exp $
00004 //
00005 #include "copyright.h"
00006 #include "autoconf.h"
00007 #include "config.h"
00008 #include "externs.h"
00009 
00010 // Do not use the following structure. It is only used to define the
00011 // POOLHDR that follows. The fields in the following structure must
00012 // match POOLHDR in type and order. Doing it this way is a workaround
00013 // for compilers not supporting #pragma pack(sizeof(INT64)).
00014 //
00015 typedef struct pool_header_unaligned
00016 {
00017     unsigned int        magicnum;   // For consistency check
00018     size_t              pool_size;  // For consistency check
00019     struct pool_header *next;       // Next pool header in chain
00020     struct pool_header *nxtfree;    // Next pool header in freelist
00021     char               *buf_tag;    // Debugging/trace tag
00022 } POOLHDR_UNALIGNED;
00023 
00024 // The following structure is 64-bit aligned. The fields in the
00025 // following structure must match POOLHDR_UNALIGNED in type and
00026 // order.
00027 //
00028 typedef struct pool_header
00029 {
00030     unsigned int        magicnum;   // For consistency check
00031     size_t              pool_size;  // For consistency check
00032     struct pool_header *next;       // Next pool header in chain
00033     struct pool_header *nxtfree;    // Next pool header in freelist
00034     char               *buf_tag;    // Debugging/trace tag
00035     char  PaddingTo64bits[7 - ((sizeof(POOLHDR_UNALIGNED)-1) & 7)];
00036 } POOLHDR;
00037 
00038 typedef struct pool_footer
00039 {
00040     unsigned int magicnum;          // For consistency check
00041 } POOLFTR;
00042 
00043 typedef struct pooldata
00044 {
00045     size_t pool_size;               // Size in bytes of a buffer
00046     unsigned int poolmagic;         // Magic number specific to this pool
00047     POOLHDR *free_head;             // Buffer freelist head
00048     POOLHDR *chain_head;            // Buffer chain head
00049     UINT64 tot_alloc;               // Total buffers allocated
00050     UINT64 num_alloc;               // Number of buffers currently allocated
00051     UINT64 max_alloc;               // Max # buffers allocated at one time
00052     UINT64 num_lost;                // Buffers lost due to corruption
00053 } POOL;
00054 
00055 static POOL pools[NUM_POOLS];
00056 static const char *poolnames[] =
00057 {
00058     "Lbufs", "Sbufs", "Mbufs", "Bools", "Descs", "Qentries", "Pcaches"
00059 };
00060 
00061 void pool_init(int poolnum, int poolsize)
00062 {
00063     pools[poolnum].pool_size = poolsize;
00064     pools[poolnum].poolmagic = CRC32_ProcessInteger2(poolnum, poolsize);
00065     pools[poolnum].free_head = NULL;
00066     pools[poolnum].chain_head = NULL;
00067     pools[poolnum].tot_alloc = 0;
00068     pools[poolnum].num_alloc = 0;
00069     pools[poolnum].max_alloc = 0;
00070     pools[poolnum].num_lost = 0;
00071 }
00072 
00073 static void pool_err
00074 (
00075     const char *logsys,
00076     int         logflag,
00077     int         poolnum,
00078     const char *tag,
00079     POOLHDR    *ph,
00080     const char *action,
00081     const char *reason,
00082     const char *file,
00083     const int   line
00084 )
00085 {
00086     if (mudstate.logging == 0)
00087     {
00088         STARTLOG(logflag, logsys, "ALLOC");
00089         Log.tinyprintf("%s[%d] (tag %s) %s in %s line %d at %lx. (%s)", action,
00090             pools[poolnum].pool_size, tag, reason, file, line, (long)ph,
00091             mudstate.debug_cmd);
00092         ENDLOG;
00093     }
00094     else if (logflag != LOG_ALLOCATE)
00095     {
00096         Log.tinyprintf(ENDLINE "***< %s[%d] (tag %s) %s in %s line %d at %lx. >***",
00097             action, pools[poolnum].pool_size, tag, reason, file, line, (long)ph);
00098     }
00099 }
00100 
00101 static void pool_vfy(int poolnum, const char *tag, const char *file, const int line)
00102 {
00103     POOLHDR *ph, *lastph;
00104     POOLFTR *pf;
00105     char *h;
00106 
00107     lastph = NULL;
00108     size_t psize = pools[poolnum].pool_size;
00109     for (ph = pools[poolnum].chain_head; ph; lastph = ph, ph = ph->next)
00110     {
00111         h = (char *)ph;
00112         h += sizeof(POOLHDR);
00113         h += pools[poolnum].pool_size;
00114         pf = (POOLFTR *) h;
00115 
00116         if (ph->magicnum != pools[poolnum].poolmagic)
00117         {
00118             pool_err("BUG", LOG_ALWAYS, poolnum, tag, ph, "Verify",
00119                      "header corrupted (clearing freelist)", file, line);
00120 
00121             // Break the header chain at this point so we don't
00122             // generate an error for EVERY alloc and free, also we
00123             // can't continue the scan because the next pointer might
00124             // be trash too.
00125             //
00126             if (lastph)
00127             {
00128                 lastph->next = NULL;
00129             }
00130             else
00131             {
00132                 pools[poolnum].chain_head = NULL;
00133             }
00134 
00135             // It's not safe to continue.
00136             //
00137             return;
00138         }
00139         if (pf->magicnum != pools[poolnum].poolmagic)
00140         {
00141             pool_err("BUG", LOG_ALWAYS, poolnum, tag, ph, "Verify",
00142                 "footer corrupted", file, line);
00143             pf->magicnum = pools[poolnum].poolmagic;
00144         }
00145         if (ph->pool_size != psize)
00146         {
00147             pool_err("BUG", LOG_ALWAYS, poolnum, tag, ph,
00148                  "Verify", "header has incorrect size", file, line);
00149         }
00150     }
00151 }
00152 
00153 static void pool_check(const char *tag, const char *file, const int line)
00154 {
00155     int i;
00156     for (i = 0; i < NUM_POOLS; i++)
00157     {
00158         pool_vfy(i, tag, file, line);
00159     }
00160 }
00161 
00162 char *pool_alloc(int poolnum, const char *tag, const char *file, const int line)
00163 {
00164     if (mudconf.paranoid_alloc)
00165     {
00166         pool_check(tag, file, line);
00167     }
00168 
00169     char *p;
00170     POOLFTR *pf;
00171     POOLHDR *ph = (POOLHDR *)pools[poolnum].free_head;
00172     if (  ph
00173        && ph->magicnum == pools[poolnum].poolmagic)
00174     {
00175         p = (char *)(ph + 1);
00176         pf = (POOLFTR *)(p + pools[poolnum].pool_size);
00177         pools[poolnum].free_head = ph->nxtfree;
00178 
00179         // Check for corrupted footer, just report and fix it.
00180         //
00181         if (pf->magicnum != pools[poolnum].poolmagic)
00182         {
00183             pool_err("BUG", LOG_ALWAYS, poolnum, tag, ph, "Alloc",
00184                 "corrupted buffer footer", file, line);
00185             pf->magicnum = pools[poolnum].poolmagic;
00186         }
00187     }
00188     else
00189     {
00190         if (ph)
00191         {
00192             // Header is corrupt. Throw away the freelist and start a new
00193             // one.
00194             pool_err("BUG", LOG_ALWAYS, poolnum, tag, ph, "Alloc",
00195                 "corrupted buffer header", file, line);
00196 
00197             // Start a new free list and record stats.
00198             //
00199             pools[poolnum].free_head = NULL;
00200             pools[poolnum].num_lost += (pools[poolnum].tot_alloc
00201                                      -  pools[poolnum].num_alloc);
00202             pools[poolnum].tot_alloc = pools[poolnum].num_alloc;
00203         }
00204 
00205         ph = (POOLHDR *)MEMALLOC(pools[poolnum].pool_size + sizeof(POOLHDR)
00206            + sizeof(POOLFTR));
00207         ISOUTOFMEMORY(ph);
00208         p = (char *)(ph + 1);
00209         pf = (POOLFTR *)(p + pools[poolnum].pool_size);
00210 
00211         // Initialize.
00212         //
00213         ph->next = pools[poolnum].chain_head;
00214         ph->nxtfree = NULL;
00215         ph->magicnum = pools[poolnum].poolmagic;
00216         ph->pool_size = pools[poolnum].pool_size;
00217         pf->magicnum = pools[poolnum].poolmagic;
00218         *((unsigned int *)p) = pools[poolnum].poolmagic;
00219         pools[poolnum].chain_head = ph;
00220         pools[poolnum].max_alloc++;
00221     }
00222 
00223     ph->buf_tag = (char *)tag;
00224     pools[poolnum].tot_alloc++;
00225     pools[poolnum].num_alloc++;
00226 
00227     if (  (LOG_ALLOCATE & mudconf.log_options)
00228        && mudstate.logging == 0
00229        && start_log("DBG", "ALLOC"))
00230     {
00231         Log.tinyprintf("Alloc[%d] (tag %s) in %s line %d buffer at %lx. (%s)",
00232             pools[poolnum].pool_size, tag, file, line, (long)ph, mudstate.debug_cmd);
00233         end_log();
00234     }
00235 
00236     // If the buffer was modified after it was last freed, log it.
00237     //
00238     unsigned int *pui = (unsigned int *)p;
00239     if (*pui != pools[poolnum].poolmagic)
00240     {
00241         pool_err("BUG", LOG_PROBLEMS, poolnum, tag, ph, "Alloc",
00242             "buffer modified after free", file, line);
00243     }
00244     *pui = 0;
00245     return p;
00246 }
00247 
00248 char *pool_alloc_lbuf(const char *tag, const char *file, const int line)
00249 {
00250     if (mudconf.paranoid_alloc)
00251     {
00252         pool_check(tag, file, line);
00253     }
00254 
00255     char *p;
00256     POOLFTR *pf;
00257     POOLHDR *ph = (POOLHDR *)pools[POOL_LBUF].free_head;
00258     if (  ph
00259        && ph->magicnum == pools[POOL_LBUF].poolmagic)
00260     {
00261         p = (char *)(ph + 1);
00262         pf = (POOLFTR *)(p + LBUF_SIZE);
00263         pools[POOL_LBUF].free_head = ph->nxtfree;
00264 
00265         // Check for corrupted footer, just report and fix it.
00266         //
00267         if (pf->magicnum != pools[POOL_LBUF].poolmagic)
00268         {
00269             pool_err("BUG", LOG_ALWAYS, POOL_LBUF, tag, ph, "Alloc",
00270                 "corrupted buffer footer", file, line);
00271             pf->magicnum = pools[POOL_LBUF].poolmagic;
00272         }
00273     }
00274     else
00275     {
00276         if (ph)
00277         {
00278             // Header is corrupt. Throw away the freelist and start a new
00279             // one.
00280             pool_err("BUG", LOG_ALWAYS, POOL_LBUF, tag, ph, "Alloc",
00281                 "corrupted buffer header", file, line);
00282 
00283             // Start a new free list and record stats.
00284             //
00285             pools[POOL_LBUF].free_head = NULL;
00286             pools[POOL_LBUF].num_lost += (pools[POOL_LBUF].tot_alloc
00287                                      -  pools[POOL_LBUF].num_alloc);
00288             pools[POOL_LBUF].tot_alloc = pools[POOL_LBUF].num_alloc;
00289         }
00290 
00291         ph = (POOLHDR *)MEMALLOC(LBUF_SIZE + sizeof(POOLHDR)
00292            + sizeof(POOLFTR));
00293         ISOUTOFMEMORY(ph);
00294         p = (char *)(ph + 1);
00295         pf = (POOLFTR *)(p + LBUF_SIZE);
00296 
00297         // Initialize.
00298         //
00299         ph->next = pools[POOL_LBUF].chain_head;
00300         ph->nxtfree = NULL;
00301         ph->magicnum = pools[POOL_LBUF].poolmagic;
00302         ph->pool_size = LBUF_SIZE;
00303         pf->magicnum = pools[POOL_LBUF].poolmagic;
00304         *((unsigned int *)p) = pools[POOL_LBUF].poolmagic;
00305         pools[POOL_LBUF].chain_head = ph;
00306         pools[POOL_LBUF].max_alloc++;
00307     }
00308 
00309     ph->buf_tag = (char *)tag;
00310     pools[POOL_LBUF].tot_alloc++;
00311     pools[POOL_LBUF].num_alloc++;
00312 
00313     if (  (LOG_ALLOCATE & mudconf.log_options)
00314        && mudstate.logging == 0
00315        && start_log("DBG", "ALLOC"))
00316     {
00317         Log.tinyprintf("Alloc[%d] (tag %s) in %s line %d buffer at %lx. (%s)",
00318             LBUF_SIZE, tag, file, line, (long)ph, mudstate.debug_cmd);
00319         end_log();
00320     }
00321 
00322     // If the buffer was modified after it was last freed, log it.
00323     //
00324     unsigned int *pui = (unsigned int *)p;
00325     if (*pui != pools[POOL_LBUF].poolmagic)
00326     {
00327         pool_err("BUG", LOG_PROBLEMS, POOL_LBUF, tag, ph, "Alloc",
00328             "buffer modified after free", file, line);
00329     }
00330     *pui = 0;
00331     return p;
00332 }
00333 
00334 void pool_free(int poolnum, char *buf, const char *file, const int line)
00335 {
00336     if (buf == NULL)
00337     {
00338         STARTLOG(LOG_PROBLEMS, "BUG", "ALLOC")
00339         log_text(tprintf("Attempt to free null pointer in %s line %d.", file, line));
00340         ENDLOG
00341         return;
00342     }
00343     POOLHDR *ph = ((POOLHDR *)(buf)) - 1;
00344     POOLFTR *pf = (POOLFTR *)(buf + pools[poolnum].pool_size);
00345     unsigned int *pui = (unsigned int *)buf;
00346 
00347     if (mudconf.paranoid_alloc)
00348     {
00349         pool_check(ph->buf_tag, file, line);
00350     }
00351 
00352     // Make sure the buffer header is good.  If it isn't, log the error and
00353     // throw away the buffer.
00354     //
00355     if (ph->magicnum != pools[poolnum].poolmagic)
00356     {
00357         pool_err("BUG", LOG_ALWAYS, poolnum, ph->buf_tag, ph, "Free",
00358                  "corrupted buffer header", file, line);
00359         pools[poolnum].num_lost++;
00360         pools[poolnum].num_alloc--;
00361         pools[poolnum].tot_alloc--;
00362         return;
00363     }
00364 
00365     // Verify the buffer footer.  Don't unlink if damaged, just repair.
00366     //
00367     if (pf->magicnum != pools[poolnum].poolmagic)
00368     {
00369         pool_err("BUG", LOG_ALWAYS, poolnum, ph->buf_tag, ph, "Free",
00370              "corrupted buffer footer", file, line);
00371         pf->magicnum = pools[poolnum].poolmagic;
00372     }
00373 
00374     // Verify that we are not trying to free someone else's buffer.
00375     //
00376     if (ph->pool_size != pools[poolnum].pool_size)
00377     {
00378         pool_err("BUG", LOG_ALWAYS, poolnum, ph->buf_tag, ph, "Free",
00379                  "Attempt to free into a different pool.", file, line);
00380         return;
00381     }
00382 
00383     if (  (LOG_ALLOCATE & mudconf.log_options)
00384        && mudstate.logging == 0
00385        && start_log("DBG", "ALLOC"))
00386     {
00387         Log.tinyprintf("Free[%d] (tag %s) in %s line %d buffer at %lx. (%s)",
00388             pools[poolnum].pool_size, ph->buf_tag, file, line, (long)ph,
00389             mudstate.debug_cmd);
00390         end_log();
00391     }
00392 
00393     // Make sure we aren't freeing an already free buffer.  If we are, log an
00394     // error, otherwise update the pool header and stats.
00395     //
00396     if (*pui == pools[poolnum].poolmagic)
00397     {
00398         pool_err("BUG", LOG_BUGS, poolnum, ph->buf_tag, ph, "Free",
00399                  "buffer already freed", file, line);
00400     }
00401     else
00402     {
00403         *pui = pools[poolnum].poolmagic;
00404         ph->nxtfree = pools[poolnum].free_head;
00405         pools[poolnum].free_head = ph;
00406         pools[poolnum].num_alloc--;
00407     }
00408 }
00409 
00410 void pool_free_lbuf(char *buf, const char *file, const int line)
00411 {
00412     if (buf == NULL)
00413     {
00414         STARTLOG(LOG_PROBLEMS, "BUG", "ALLOC")
00415         log_text(tprintf("Attempt to free_lbuf null pointer in %s line %d.", file, line));
00416         ENDLOG
00417         return;
00418     }
00419     POOLHDR *ph = ((POOLHDR *)(buf)) - 1;
00420     POOLFTR *pf = (POOLFTR *)(buf + LBUF_SIZE);
00421     unsigned int *pui = (unsigned int *)buf;
00422 
00423     if (mudconf.paranoid_alloc)
00424     {
00425         pool_check(ph->buf_tag, file, line);
00426     }
00427 
00428     if (  ph->magicnum != pools[POOL_LBUF].poolmagic
00429        || pf->magicnum != pools[POOL_LBUF].poolmagic
00430        || ph->pool_size != LBUF_SIZE
00431        || *pui == pools[POOL_LBUF].poolmagic)
00432     {
00433         if (ph->magicnum != pools[POOL_LBUF].poolmagic)
00434         {
00435             // The buffer header is damaged. Log the error and throw away the
00436             // buffer.
00437             //
00438             pool_err("BUG", LOG_ALWAYS, POOL_LBUF, ph->buf_tag, ph, "Free",
00439                      "corrupted buffer header", file, line);
00440             pools[POOL_LBUF].num_lost++;
00441             pools[POOL_LBUF].num_alloc--;
00442             pools[POOL_LBUF].tot_alloc--;
00443             return;
00444         }
00445         else if (pf->magicnum != pools[POOL_LBUF].poolmagic)
00446         {
00447             // The buffer footer is damaged.  Don't unlink, just repair.
00448             //
00449             pool_err("BUG", LOG_ALWAYS, POOL_LBUF, ph->buf_tag, ph, "Free",
00450                 "corrupted buffer footer", file, line);
00451             pf->magicnum = pools[POOL_LBUF].poolmagic;
00452         }
00453         else if (ph->pool_size != LBUF_SIZE)
00454         {
00455             // We are trying to free someone else's buffer.
00456             //
00457             pool_err("BUG", LOG_ALWAYS, POOL_LBUF, ph->buf_tag, ph, "Free",
00458                 "Attempt to free into a different pool.", file, line);
00459             return;
00460         }
00461 
00462         // If we are freeing a buffer that was already free, report an error.
00463         //
00464         if (*pui == pools[POOL_LBUF].poolmagic)
00465         {
00466             pool_err("BUG", LOG_BUGS, POOL_LBUF, ph->buf_tag, ph, "Free",
00467                      "buffer already freed", file, line);
00468             return;
00469         }
00470     }
00471 
00472     if (  (LOG_ALLOCATE & mudconf.log_options)
00473        && mudstate.logging == 0
00474        && start_log("DBG", "ALLOC"))
00475     {
00476         Log.tinyprintf("Free[%d] (tag %s) in %s line %d buffer at %lx. (%s)",
00477             LBUF_SIZE, ph->buf_tag, file, line, (long)ph, mudstate.debug_cmd);
00478         end_log();
00479     }
00480 
00481     // Update the pool header and stats.
00482     //
00483     *pui = pools[POOL_LBUF].poolmagic;
00484     ph->nxtfree = pools[POOL_LBUF].free_head;
00485     pools[POOL_LBUF].free_head = ph;
00486     pools[POOL_LBUF].num_alloc--;
00487 }
00488 
00489 static void pool_trace(dbref player, int poolnum, const char *text)
00490 {
00491     POOLHDR *ph;
00492     int numfree = 0;
00493     notify(player, tprintf("----- %s -----", text));
00494     for (ph = pools[poolnum].chain_head; ph != NULL; ph = ph->next)
00495     {
00496         if (ph->magicnum != pools[poolnum].poolmagic)
00497         {
00498             notify(player, "*** CORRUPTED BUFFER HEADER, ABORTING SCAN ***");
00499             notify(player, tprintf("%d free %s (before corruption)",
00500                        numfree, text));
00501             return;
00502         }
00503         char *h = (char *)ph;
00504         h += sizeof(POOLHDR);
00505         unsigned int *ibuf = (unsigned int *)h;
00506         if (*ibuf != pools[poolnum].poolmagic)
00507         {
00508             notify(player, ph->buf_tag);
00509         }
00510         else
00511         {
00512             numfree++;
00513         }
00514     }
00515     notify(player, tprintf("%d free %s", numfree, text));
00516 }
00517 
00518 void list_bufstats(dbref player)
00519 {
00520     char buff[MBUF_SIZE];
00521 
00522     notify(player, "Buffer Stats  Size     InUse     Total        Allocs   Lost");
00523 
00524     int i;
00525     for (i = 0; i < NUM_POOLS; i++)
00526     {
00527         char szNumAlloc[22];
00528         char szMaxAlloc[22];
00529         char szTotAlloc[22];
00530         char szNumLost[22];
00531 
00532         mux_i64toa(pools[i].num_alloc, szNumAlloc);
00533         mux_i64toa(pools[i].max_alloc, szMaxAlloc);
00534         mux_i64toa(pools[i].tot_alloc, szTotAlloc);
00535         mux_i64toa(pools[i].num_lost,  szNumLost);
00536 
00537         sprintf(buff, "%-12s %5d%10s%10s%14s%7s",
00538             poolnames[i], (int)pools[i].pool_size,
00539             szNumAlloc, szMaxAlloc, szTotAlloc, szNumLost);
00540         notify(player, buff);
00541     }
00542 }
00543 
00544 void list_buftrace(dbref player)
00545 {
00546     int i;
00547     for (i = 0; i < NUM_POOLS; i++)
00548     {
00549         pool_trace(player, i, poolnames[i]);
00550     }
00551 }
00552 
00553 void pool_reset(void)
00554 {
00555     int i;
00556     for (i = 0; i < NUM_POOLS; i++)
00557     {
00558         POOLHDR *newchain = NULL;
00559         POOLHDR *phnext;
00560         POOLHDR *ph;
00561         for (ph = pools[i].chain_head; ph != NULL; ph = phnext)
00562         {
00563             char *h = (char *)ph;
00564             phnext = ph->next;
00565             h += sizeof(POOLHDR);
00566             unsigned int *ibuf = (unsigned int *)h;
00567             if (*ibuf == pools[i].poolmagic)
00568             {
00569                 MEMFREE(ph);
00570                 ph = NULL;
00571             }
00572             else
00573             {
00574                 ph->next = newchain;
00575                 newchain = ph;
00576                 ph->nxtfree = NULL;
00577             }
00578         }
00579         pools[i].chain_head = newchain;
00580         pools[i].free_head = NULL;
00581         pools[i].max_alloc = pools[i].num_alloc;
00582     }
00583 }
00584 

Generated on Mon May 28 04:40:07 2007 for MUX by  doxygen 1.4.7