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