1: /*
   2:  * Copyright (c) 1983 Regents of the University of California.
   3:  * All rights reserved.  The Berkeley software License Agreement
   4:  * specifies the terms and conditions for redistribution.
   5:  */
   6: 
   7: #if defined(LIBC_SCCS) && !defined(lint)
   8: static char sccsid[] = "@(#)malloc.c	5.6 (Berkeley) 3/9/86";
   9: #endif LIBC_SCCS and not lint
  10: 
  11: /*
  12:  * malloc.c (Caltech) 2/21/82
  13:  * Chris Kingsley, kingsley@cit-20.
  14:  *
  15:  * This is a very fast storage allocator.  It allocates blocks of a small
  16:  * number of different sizes, and keeps free lists of each size.  Blocks that
  17:  * don't exactly fit are passed up to the next larger size.  In this
  18:  * implementation, the available sizes are 2^n-4 (or 2^n-10) bytes long.
  19:  * This is designed for use in a virtual memory environment.
  20:  */
  21: 
  22: #include <sys/types.h>
  23: 
  24: #define NULL 0
  25: 
  26: /*
  27:  * The overhead on a block is at least 4 bytes.  When free, this space
  28:  * contains a pointer to the next free block, and the bottom two bits must
  29:  * be zero.  When in use, the first byte is set to MAGIC, and the second
  30:  * byte is the size index.  The remaining bytes are for alignment.
  31:  * If range checking is enabled then a second word holds the size of the
  32:  * requested block, less 1, rounded up to a multiple of sizeof(RMAGIC).
  33:  * The order of elements is critical: ov_magic must overlay the low order
  34:  * bits of ov_next, and ov_magic can not be a valid ov_next bit pattern.
  35:  */
  36: union   overhead {
  37:     union   overhead *ov_next;  /* when free */
  38:     struct {
  39:         u_char  ovu_magic;  /* magic number */
  40:         u_char  ovu_index;  /* bucket # */
  41: #ifdef RCHECK
  42:         u_short ovu_rmagic; /* range magic number */
  43:         u_int   ovu_size;   /* actual block size */
  44: #endif
  45:     } ovu;
  46: #define ov_magic    ovu.ovu_magic
  47: #define ov_index    ovu.ovu_index
  48: #define ov_rmagic   ovu.ovu_rmagic
  49: #define ov_size     ovu.ovu_size
  50: };
  51: 
  52: #define MAGIC       0xef        /* magic # on accounting info */
  53: #define RMAGIC      0x5555      /* magic # on range info */
  54: 
  55: #ifdef RCHECK
  56: #define RSLOP       sizeof (u_short)
  57: #else
  58: #define RSLOP       0
  59: #endif
  60: 
  61: /*
  62:  * nextf[i] is the pointer to the next free block of size 2^(i+3).  The
  63:  * smallest allocatable block is 8 bytes.  The overhead information
  64:  * precedes the data area returned to the user.
  65:  */
  66: #define NBUCKETS 30
  67: static  union overhead *nextf[NBUCKETS];
  68: extern  char *sbrk();
  69: 
  70: static  int pagesz;         /* page size */
  71: static  int pagebucket;         /* page size bucket */
  72: 
  73: #ifdef MSTATS
  74: /*
  75:  * nmalloc[i] is the difference between the number of mallocs and frees
  76:  * for a given block size.
  77:  */
  78: static  u_int nmalloc[NBUCKETS];
  79: #include <stdio.h>
  80: #endif
  81: 
  82: #if defined(DEBUG) || defined(RCHECK)
  83: #define ASSERT(p)   if (!(p)) botch("p")
  84: #include <stdio.h>
  85: static
  86: botch(s)
  87:     char *s;
  88: {
  89:     fprintf(stderr, "\r\nassertion botched: %s\r\n", s);
  90:     (void) fflush(stderr);      /* just in case user buffered it */
  91:     abort();
  92: }
  93: #else
  94: #define ASSERT(p)
  95: #endif
  96: 
  97: char *
  98: malloc(nbytes)
  99:     unsigned nbytes;
 100: {
 101:     register union overhead *op;
 102:     register int bucket;
 103:     register unsigned amt, n;
 104: 
 105:     /*
 106: 	 * First time malloc is called, setup page size and
 107: 	 * align break pointer so all data will be page aligned.
 108: 	 */
 109:     if (pagesz == 0) {
 110:         pagesz = n = getpagesize();
 111:         op = (union overhead *)sbrk(0);
 112:         n = n - sizeof (*op) - ((int)op & (n - 1));
 113:         if (n < 0)
 114:             n += pagesz;
 115:         if (n) {
 116:             if (sbrk(n) == (char *)-1)
 117:                 return (NULL);
 118:         }
 119:         bucket = 0;
 120:         amt = 8;
 121:         while (pagesz > amt) {
 122:             amt <<= 1;
 123:             bucket++;
 124:         }
 125:         pagebucket = bucket;
 126:     }
 127:     /*
 128: 	 * Convert amount of memory requested into closest block size
 129: 	 * stored in hash buckets which satisfies request.
 130: 	 * Account for space used per block for accounting.
 131: 	 */
 132:     if (nbytes <= (n = pagesz - sizeof (*op) - RSLOP)) {
 133: #ifndef RCHECK
 134:         amt = 8;    /* size of first bucket */
 135:         bucket = 0;
 136: #else
 137:         amt = 16;   /* size of first bucket */
 138:         bucket = 1;
 139: #endif
 140:         n = -(sizeof (*op) + RSLOP);
 141:     } else {
 142:         amt = pagesz;
 143:         bucket = pagebucket;
 144:     }
 145:     while (nbytes > amt + n) {
 146:         amt <<= 1;
 147:         if (amt == 0)
 148:             return (NULL);
 149:         bucket++;
 150:     }
 151:     /*
 152: 	 * If nothing in hash bucket right now,
 153: 	 * request more memory from the system.
 154: 	 */
 155:     if ((op = nextf[bucket]) == NULL) {
 156:         morecore(bucket);
 157:         if ((op = nextf[bucket]) == NULL)
 158:             return (NULL);
 159:     }
 160:     /* remove from linked list */
 161:     nextf[bucket] = op->ov_next;
 162:     op->ov_magic = MAGIC;
 163:     op->ov_index = bucket;
 164: #ifdef MSTATS
 165:     nmalloc[bucket]++;
 166: #endif
 167: #ifdef RCHECK
 168:     /*
 169: 	 * Record allocated size of block and
 170: 	 * bound space with magic numbers.
 171: 	 */
 172:     op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1);
 173:     op->ov_rmagic = RMAGIC;
 174:     *(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;
 175: #endif
 176:     return ((char *)(op + 1));
 177: }
 178: 
 179: /*
 180:  * Allocate more memory to the indicated bucket.
 181:  */
 182: morecore(bucket)
 183:     int bucket;
 184: {
 185:     register union overhead *op;
 186:     register int sz;        /* size of desired block */
 187:     int amt;            /* amount to allocate */
 188:     int nblks;          /* how many blocks we get */
 189: 
 190:     /*
 191: 	 * sbrk_size <= 0 only for big, FLUFFY, requests (about
 192: 	 * 2^30 bytes on a VAX, I think) or for a negative arg.
 193: 	 */
 194:     sz = 1 << (bucket + 3);
 195: #ifdef DEBUG
 196:     ASSERT(sz > 0);
 197: #else
 198:     if (sz <= 0)
 199:         return;
 200: #endif
 201:     if (sz < pagesz) {
 202:         amt = pagesz;
 203:         nblks = amt / sz;
 204:     } else {
 205:         amt = sz + pagesz;
 206:         nblks = 1;
 207:     }
 208:     op = (union overhead *)sbrk(amt);
 209:     /* no more room! */
 210:     if ((int)op == -1)
 211:         return;
 212:     /*
 213: 	 * Add new memory allocated to that on
 214: 	 * free list for this hash bucket.
 215: 	 */
 216:     nextf[bucket] = op;
 217:     while (--nblks > 0) {
 218:         op->ov_next = (union overhead *)((caddr_t)op + sz);
 219:         op = (union overhead *)((caddr_t)op + sz);
 220:     }
 221: }
 222: 
 223: free(cp)
 224:     char *cp;
 225: {
 226:     register int size;
 227:     register union overhead *op;
 228: 
 229:     if (cp == NULL)
 230:         return;
 231:     op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
 232: #ifdef DEBUG
 233:     ASSERT(op->ov_magic == MAGIC);      /* make sure it was in use */
 234: #else
 235:     if (op->ov_magic != MAGIC)
 236:         return;             /* sanity */
 237: #endif
 238: #ifdef RCHECK
 239:     ASSERT(op->ov_rmagic == RMAGIC);
 240:     ASSERT(*(u_short *)((caddr_t)(op + 1) + op->ov_size) == RMAGIC);
 241: #endif
 242:     size = op->ov_index;
 243:     ASSERT(size < NBUCKETS);
 244:     op->ov_next = nextf[size];  /* also clobbers ov_magic */
 245:     nextf[size] = op;
 246: #ifdef MSTATS
 247:     nmalloc[size]--;
 248: #endif
 249: }
 250: 
 251: /*
 252:  * When a program attempts "storage compaction" as mentioned in the
 253:  * old malloc man page, it realloc's an already freed block.  Usually
 254:  * this is the last block it freed; occasionally it might be farther
 255:  * back.  We have to search all the free lists for the block in order
 256:  * to determine its bucket: 1st we make one pass thru the lists
 257:  * checking only the first block in each; if that fails we search
 258:  * ``realloc_srchlen'' blocks in each list for a match (the variable
 259:  * is extern so the caller can modify it).  If that fails we just copy
 260:  * however many bytes was given to realloc() and hope it's not huge.
 261:  */
 262: int realloc_srchlen = 4;    /* 4 should be plenty, -1 =>'s whole list */
 263: 
 264: char *
 265: realloc(cp, nbytes)
 266:     char *cp;
 267:     unsigned nbytes;
 268: {
 269:     register u_int onb, i;
 270:     union overhead *op;
 271:     char *res;
 272:     int was_alloced = 0;
 273: 
 274:     if (cp == NULL)
 275:         return (malloc(nbytes));
 276:     op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
 277:     if (op->ov_magic == MAGIC) {
 278:         was_alloced++;
 279:         i = op->ov_index;
 280:     } else {
 281:         /*
 282: 		 * Already free, doing "compaction".
 283: 		 *
 284: 		 * Search for the old block of memory on the
 285: 		 * free list.  First, check the most common
 286: 		 * case (last element free'd), then (this failing)
 287: 		 * the last ``realloc_srchlen'' items free'd.
 288: 		 * If all lookups fail, then assume the size of
 289: 		 * the memory block being realloc'd is the
 290: 		 * largest possible (so that all "nbytes" of new
 291: 		 * memory are copied into).  Note that this could cause
 292: 		 * a memory fault if the old area was tiny, and the moon
 293: 		 * is gibbous.  However, that is very unlikely.
 294: 		 */
 295:         if ((i = findbucket(op, 1)) < 0 &&
 296:             (i = findbucket(op, realloc_srchlen)) < 0)
 297:             i = NBUCKETS;
 298:     }
 299:     onb = 1 << (i + 3);
 300:     if (onb < pagesz)
 301:         onb -= sizeof (*op) + RSLOP;
 302:     else
 303:         onb += pagesz - sizeof (*op) - RSLOP;
 304:     /* avoid the copy if same size block */
 305:     if (was_alloced) {
 306:         if (i) {
 307:             i = 1 << (i + 2);
 308:             if (i < pagesz)
 309:                 i -= sizeof (*op) + RSLOP;
 310:             else
 311:                 i += pagesz - sizeof (*op) - RSLOP;
 312:         }
 313:         if (nbytes <= onb && nbytes > i) {
 314: #ifdef RCHECK
 315:             op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1);
 316:             *(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;
 317: #endif
 318:             return(cp);
 319:         } else
 320:             free(cp);
 321:     }
 322:     if ((res = malloc(nbytes)) == NULL)
 323:         return (NULL);
 324:     if (cp != res)      /* common optimization if "compacting" */
 325:         bcopy(cp, res, (nbytes < onb) ? nbytes : onb);
 326:     return (res);
 327: }
 328: 
 329: /*
 330:  * Search ``srchlen'' elements of each free list for a block whose
 331:  * header starts at ``freep''.  If srchlen is -1 search the whole list.
 332:  * Return bucket number, or -1 if not found.
 333:  */
 334: static
 335: findbucket(freep, srchlen)
 336:     union overhead *freep;
 337:     int srchlen;
 338: {
 339:     register union overhead *p;
 340:     register int i, j;
 341: 
 342:     for (i = 0; i < NBUCKETS; i++) {
 343:         j = 0;
 344:         for (p = nextf[i]; p && j != srchlen; p = p->ov_next) {
 345:             if (p == freep)
 346:                 return (i);
 347:             j++;
 348:         }
 349:     }
 350:     return (-1);
 351: }
 352: 
 353: #ifdef MSTATS
 354: /*
 355:  * mstats - print out statistics about malloc
 356:  *
 357:  * Prints two lines of numbers, one showing the length of the free list
 358:  * for each size category, the second showing the number of mallocs -
 359:  * frees for each size category.
 360:  */
 361: mstats(s)
 362:     char *s;
 363: {
 364:     register int i, j;
 365:     register union overhead *p;
 366:     int totfree = 0,
 367:     totused = 0;
 368: 
 369:     fprintf(stderr, "Memory allocation statistics %s\nfree:\t", s);
 370:     for (i = 0; i < NBUCKETS; i++) {
 371:         for (j = 0, p = nextf[i]; p; p = p->ov_next, j++)
 372:             ;
 373:         fprintf(stderr, " %d", j);
 374:         totfree += j * (1 << (i + 3));
 375:     }
 376:     fprintf(stderr, "\nused:\t");
 377:     for (i = 0; i < NBUCKETS; i++) {
 378:         fprintf(stderr, " %d", nmalloc[i]);
 379:         totused += nmalloc[i] * (1 << (i + 3));
 380:     }
 381:     fprintf(stderr, "\n\tTotal in use: %d, total free: %d\n",
 382:         totused, totfree);
 383: }
 384: #endif

Defined functions

botch defined in line 85; used 1 times
  • in line 83
findbucket defined in line 334; used 2 times
free defined in line 223; used 1339 times
malloc defined in line 97; used 1140 times
morecore defined in line 182; used 1 times
mstats defined in line 361; used 1 times
realloc defined in line 264; used 127 times

Defined variables

nextf defined in line 67; used 8 times
pagebucket defined in line 71; used 2 times
pagesz defined in line 70; used 13 times
realloc_srchlen defined in line 262; used 1 times
sccsid defined in line 8; never used

Defined union's

overhead defined in line 36; used 34 times

Defined macros

ASSERT defined in line 94; used 5 times
MAGIC defined in line 52; used 4 times
NBUCKETS defined in line 66; used 7 times
NULL defined in line 24; used 9 times
RMAGIC defined in line 53; used 5 times
RSLOP defined in line 58; used 10 times
ov_index defined in line 47; used 3 times
ov_magic defined in line 46; used 4 times
ov_rmagic defined in line 48; used 2 times
ov_size defined in line 49; used 5 times
Last modified: 1986-03-10
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2557
Valid CSS Valid XHTML 1.0 Strict