/* alloc.c - memory allocation subsystem */ #include "autoconf.h" #include "copyright.h" #ifndef lint static char RCSid[] = "$Id: alloc.c,v 1.7 1995/03/20 23:59:34 ambar Exp $"; USE(RCSid); #endif #include "alloc.h" #include "externs.h" typedef struct pool_header { int magicnum; /* For consistency check */ int pool_size; /* Another consistency check */ struct pool_header *next; /* Next pool header in chain */ struct pool_header *nxtfree; /* Next pool header in freelist */ char *buf_tag; /* Debugging/trace tag */ } POOLHDR; typedef struct pool_footer { int magicnum; /* For consistency check */ } POOLFTR; typedef struct pooldata { int pool_size; /* Size in bytes of a buffer */ POOLHDR *free_head; /* Buffer freelist head */ POOLHDR *chain_head; /* Buffer chain head */ int tot_alloc; /* Total buffers allocated */ int num_alloc; /* Number of buffers currently allocated */ int max_alloc; /* Max # buffers allocated at one time */ int num_lost; /* Buffers lost due to corruption */ } POOL; POOL pools[NUM_POOLS]; const char *poolnames[] = {"Sbufs", "Mbufs", "Lbufs", "Bools", "Descs", "Qentries", "Pcaches"}; #define POOL_MAGICNUM 0xdeadbeef void pool_init(poolnum, poolsize) int poolnum, poolsize; { pools[poolnum].pool_size = poolsize; pools[poolnum].free_head = NULL; pools[poolnum].chain_head = NULL; pools[poolnum].tot_alloc = 0; pools[poolnum].num_alloc = 0; pools[poolnum].max_alloc = 0; pools[poolnum].num_lost = 0; return; } static void pool_err(logsys, logflag, poolnum, tag, ph, action, reason) int logflag, poolnum; const char *logsys, *tag, *action, *reason; POOLHDR *ph; { if (!mudstate.logging) { STARTLOG(logflag, logsys, "ALLOC") sprintf(mudstate.buffer, "%s[%d] (tag %s) %s at %lx. (%s)", action, pools[poolnum].pool_size, tag, reason, (long) ph, mudstate.debug_cmd); log_text(mudstate.buffer); ENDLOG } else if (logflag != LOG_ALLOCATE) { sprintf(mudstate.buffer, "\n***< %s[%d] (tag %s) %s at %lx. >***", action, pools[poolnum].pool_size, tag, reason, (long) ph); log_text(mudstate.buffer); } } static void pool_vfy(poolnum, tag) int poolnum; const char *tag; { POOLHDR *ph, *lastph; POOLFTR *pf; char *h; int psize; lastph = NULL; psize = pools[poolnum].pool_size; for (ph = pools[poolnum].chain_head; ph; lastph = ph, ph = ph->next) { h = (char *) ph; h += sizeof(POOLHDR); h += pools[poolnum].pool_size; pf = (POOLFTR *) h; if (ph->magicnum != POOL_MAGICNUM) { pool_err("BUG", LOG_ALWAYS, poolnum, tag, ph, "Verify", "header corrupted (clearing freelist)"); /* Break the header chain at this point so we don't * generate an error for EVERY alloc and free, * also we can't continue the scan because the next * pointer might be trash too. */ if (lastph) lastph->next = NULL; else pools[poolnum].chain_head = NULL; return; /* not safe to continue */ } if (pf->magicnum != POOL_MAGICNUM) { pool_err("BUG", LOG_ALWAYS, poolnum, tag, ph, "Verify", "footer corrupted"); pf->magicnum = POOL_MAGICNUM; } if (ph->pool_size != psize) { pool_err("BUG", LOG_ALWAYS, poolnum, tag, ph, "Verify", "header has incorrect size"); } } } void pool_check(tag) const char *tag; { pool_vfy(POOL_LBUF, tag); pool_vfy(POOL_MBUF, tag); pool_vfy(POOL_SBUF, tag); pool_vfy(POOL_BOOL, tag); pool_vfy(POOL_DESC, tag); pool_vfy(POOL_QENTRY, tag); } char * pool_alloc(poolnum, tag) int poolnum; const char *tag; { int *p; char *h; POOLHDR *ph; POOLFTR *pf; if (mudconf.paranoid_alloc) pool_check(tag); do { if (pools[poolnum].free_head == NULL) { h = (char *) XMALLOC(pools[poolnum].pool_size + sizeof(POOLHDR) + sizeof(POOLFTR), "pool_alloc"); if (h == NULL) abort(); ph = (POOLHDR *) h; h += sizeof(POOLHDR); p = (int *) h; h += pools[poolnum].pool_size; pf = (POOLFTR *) h; ph->next = pools[poolnum].chain_head; ph->nxtfree = NULL; ph->magicnum = POOL_MAGICNUM; ph->pool_size = pools[poolnum].pool_size; pf->magicnum = POOL_MAGICNUM; *p = POOL_MAGICNUM; pools[poolnum].chain_head = ph; pools[poolnum].max_alloc++; } else { ph = (POOLHDR *) (pools[poolnum].free_head); h = (char *) ph; h += sizeof(POOLHDR); p = (int *) h; h += pools[poolnum].pool_size; pf = (POOLFTR *) h; pools[poolnum].free_head = ph->nxtfree; /* If corrupted header we need to throw away the * freelist as the freelist pointer may be corrupt. */ if (ph->magicnum != POOL_MAGICNUM) { pool_err("BUG", LOG_ALWAYS, poolnum, tag, ph, "Alloc", "corrupted buffer header"); /* Start a new free list and record stats */ p = NULL; pools[poolnum].free_head = NULL; pools[poolnum].num_lost += (pools[poolnum].tot_alloc - pools[poolnum].num_alloc); pools[poolnum].tot_alloc = pools[poolnum].num_alloc; } /* Check for corrupted footer, just report and * fix it */ if (pf->magicnum != POOL_MAGICNUM) { pool_err("BUG", LOG_ALWAYS, poolnum, tag, ph, "Alloc", "corrupted buffer footer"); pf->magicnum = POOL_MAGICNUM; } } } while (p == NULL); ph->buf_tag = (char *) tag; pools[poolnum].tot_alloc++; pools[poolnum].num_alloc++; pool_err("DBG", LOG_ALLOCATE, poolnum, tag, ph, "Alloc", "buffer"); /* If the buffer was modified after it was last freed, log it. */ if ((*p != POOL_MAGICNUM) && (!mudstate.logging)) { pool_err("BUG", LOG_PROBLEMS, poolnum, tag, ph, "Alloc", "buffer modified after free"); } *p = 0; return (char *) p; } void pool_free(poolnum, buf) int poolnum; char **buf; { int *ibuf; char *h; POOLHDR *ph; POOLFTR *pf; ibuf = (int *) *buf; h = (char *) ibuf; h -= sizeof(POOLHDR); ph = (POOLHDR *) h; h = (char *) ibuf; h += pools[poolnum].pool_size; pf = (POOLFTR *) h; if (mudconf.paranoid_alloc) pool_check(ph->buf_tag); /* Make sure the buffer header is good. If it isn't, log the error and * throw away the buffer. */ if (ph->magicnum != POOL_MAGICNUM) { pool_err("BUG", LOG_ALWAYS, poolnum, ph->buf_tag, ph, "Free", "corrupted buffer header"); pools[poolnum].num_lost++; pools[poolnum].num_alloc--; pools[poolnum].tot_alloc--; return; } /* Verify the buffer footer. Don't unlink if damaged, just repair */ if (pf->magicnum != POOL_MAGICNUM) { pool_err("BUG", LOG_ALWAYS, poolnum, ph->buf_tag, ph, "Free", "corrupted buffer footer"); pf->magicnum = POOL_MAGICNUM; } /* Verify that we aren't trying to free someone else's buffer */ if (ph->pool_size != pools[poolnum].pool_size) { pool_err("BUG", LOG_ALWAYS, poolnum, ph->buf_tag, ph, "Free", "Attempt to free into a different pool."); return; } pool_err("DBG", LOG_ALLOCATE, poolnum, ph->buf_tag, ph, "Free", "buffer"); /* Make sure we aren't freeing an already free buffer. If we are, * log an error, otherwise update the pool header and stats */ if (*ibuf == POOL_MAGICNUM) { pool_err("BUG", LOG_BUGS, poolnum, ph->buf_tag, ph, "Free", "buffer already freed"); } else { *ibuf = POOL_MAGICNUM; ph->nxtfree = pools[poolnum].free_head; pools[poolnum].free_head = ph; pools[poolnum].num_alloc--; } } static char * pool_stats(poolnum, text) int poolnum; const char *text; { char *buf; buf = alloc_mbuf("pool_stats"); sprintf(buf, "%-15s %5d%9d%9d%9d%9d", text, pools[poolnum].pool_size, pools[poolnum].num_alloc, pools[poolnum].max_alloc, pools[poolnum].tot_alloc, pools[poolnum].num_lost); return buf; } static void pool_trace(player, poolnum, text) dbref player; int poolnum; const char *text; { POOLHDR *ph; int numfree, *ibuf; char *h; numfree = 0; notify(player, tprintf("----- %s -----", text)); for (ph = pools[poolnum].chain_head; ph != NULL; ph = ph->next) { if (ph->magicnum != POOL_MAGICNUM) { notify(player, "*** CORRUPTED BUFFER HEADER, ABORTING SCAN ***"); notify(player, tprintf("%d free %s (before corruption)", numfree, text)); return; } h = (char *) ph; h += sizeof(POOLHDR); ibuf = (int *) h; if (*ibuf != POOL_MAGICNUM) notify(player, ph->buf_tag); else numfree++; } notify(player, tprintf("%d free %s", numfree, text)); } static void list_bufstat(player, poolnum, pool_name) dbref player; int poolnum; const char *pool_name; { char *buff; buff = pool_stats(poolnum, poolnames[poolnum]); notify(player, buff); free_mbuf(buff); } void list_bufstats(player) dbref player; { int i; notify(player, "Buffer Stats Size InUse Total Allocs Lost"); for (i = 0; i < NUM_POOLS; i++) list_bufstat(player, i, poolnames[i]); } void list_buftrace(player) dbref player; { int i; for (i = 0; i < NUM_POOLS; i++) pool_trace(player, i, poolnames[i]); } void pool_reset() { POOLHDR *ph, *phnext, *newchain; int i, *ibuf; char *h; for (i = 0; i < NUM_POOLS; i++) { newchain = NULL; for (ph = pools[i].chain_head; ph != NULL; ph = phnext) { h = (char *) ph; phnext = ph->next; h += sizeof(POOLHDR); ibuf = (int *) h; if (*ibuf == POOL_MAGICNUM) { free(ph); } else { if (!newchain) { newchain = ph; ph->next = NULL; } else { ph->next = newchain; newchain = ph; } ph->nxtfree = NULL; } } pools[i].chain_head = newchain; pools[i].free_head = NULL; pools[i].max_alloc = pools[i].num_alloc; } }