alloc.c

来自「<B>Digital的Unix操作系统VAX 4.2源码</B>」· C语言 代码 · 共 412 行

C
412
字号
#ifndef lintstatic char *sccsid = "@(#)alloc.c	4.2  (ULTRIX)        8/13/90";#endif/************************************************************************ *                                                                      * *                      Copyright (c) 1988 by                           * *              Digital Equipment Corporation, Maynard, MA              * *                      All rights reserved.                            * *                                                                      * *   This software is furnished under a license and may be used and     * *   copied  only  in accordance with the terms of such license and     * *   with the  inclusion  of  the  above  copyright  notice.   This     * *   software  or  any  other copies thereof may not be provided or     * *   otherwise made available to any other person.  No title to and     * *   ownership of the software is hereby transferred.                   * *                                                                      * *   The information in this software is subject to change  without     * *   notice  and should not be construed as a commitment by Digital     * *   Equipment Corporation.                                             * *                                                                      * *   Digital assumes no responsibility for the use  or  reliability     * *   of its software on equipment which is not supplied by Digital.     * *                                                                      * ************************************************************************//* ------------------------------------------------------------------ *//* | Copyright Unpublished, MIPS Computer Systems, Inc.  All Rights | *//* | Reserved.  This software contains proprietary and confidential | *//* | information of MIPS and its suppliers.  Use, disclosure or     | *//* | reproduction is prohibited without the prior express written   | *//* | consent of MIPS.                                               | *//* ------------------------------------------------------------------ *//* $Header: alloc.c,v 1.3 86/07/09 20:16:34 dce Exp $ *//* * malloc.c (Caltech) 2/21/82 * Chris Kingsley, kingsley@cit-20. * * This is a very fast storage allocator.  It allocates blocks of a small  * number of different sizes, and keeps free lists of each size.  Blocks that * don't exactly fit are passed up to the next larger size.  In this  * implementation, the available sizes are 2^n-4 (or 2^n-10) bytes long. * This is designed for use in a virtual memory environment. * * Modification History * * 001 - Bob Fontaine - Thu Jun 21 10:22:20 EDT 1990 *	 changed the name of the internal printf function to csh_printf *	 to eliminate conflicts withe the stdio printf. */#include <sys/types.h>#define	NULL 0/* * The overhead on a block is at least 4 bytes.  When free, this space * contains a pointer to the next free block, and the bottom two bits must * be zero.  When in use, the first byte is set to MAGIC, and the second * byte is the size index.  The remaining bytes are for alignment. * If range checking is enabled then a second word holds the size of the * requested block, less 1, rounded up to a multiple of sizeof(RMAGIC). * The order of elements is critical: ov_magic must overlay the low order * bits of ov_next, and ov_magic can not be a valid ov_next bit pattern. */union	overhead {	union	overhead *ov_next;	/* when free */	struct {		u_char	ovu_magic;	/* magic number */		u_char	ovu_index;	/* bucket # */#ifdef RCHECK		u_short	ovu_rmagic;	/* range magic number */		u_int	ovu_size;	/* actual block size */#endif	} ovu;#define	ov_magic	ovu.ovu_magic#define	ov_index	ovu.ovu_index#define	ov_rmagic	ovu.ovu_rmagic#define	ov_size		ovu.ovu_size};#define	MAGIC		0xef		/* magic # on accounting info */#define RMAGIC		0x5555		/* magic # on range info */#ifdef RCHECK#define	RSLOP		sizeof (u_short)#else#define	RSLOP		0#endif/* * nextf[i] is the pointer to the next free block of size 2^(i+3).  The * smallest allocatable block is 8 bytes.  The overhead information * precedes the data area returned to the user. */#define	NBUCKETS 30static	union overhead *nextf[NBUCKETS];extern	char *sbrk();static	int pagesz;			/* page size */static	int pagebucket;			/* page size bucket *//* * nmalloc[i] is the difference between the number of mallocs and frees * for a given block size. */static	u_int nmalloc[NBUCKETS];#if defined(DEBUG) || defined(RCHECK)#define	ASSERT(p)   if (!(p)) botch("p")staticbotch(s)	char *s;{	csh_printf("\r\nassertion botched: %s\r\n", s); /* 001 RNF */	abort();}#else#define	ASSERT(p)#endifchar *malloc(nbytes)	unsigned nbytes;{  	register union overhead *op;  	register int bucket;	register unsigned amt, n;	/*	 * First time malloc is called, setup page size and	 * align break pointer so all data will be page aligned.	 */	if (pagesz == 0) {		pagesz = n = getpagesize();		op = (union overhead *)sbrk(0);  		n = n - sizeof (*op) - ((int)op & (n - 1));		if (n < 0)			n += pagesz;  		if (n) {  			if (sbrk(n) == (char *)-1)				return (NULL);		}		bucket = 0;		amt = 8;		while (pagesz > amt) {			amt <<= 1;			bucket++;		}		pagebucket = bucket;	}	/*	 * Convert amount of memory requested into closest block size	 * stored in hash buckets which satisfies request.	 * Account for space used per block for accounting.	 */	if (nbytes <= (n = pagesz - sizeof (*op) - RSLOP)) {#ifndef RCHECK		amt = 8;	/* size of first bucket */		bucket = 0;#else		amt = 16;	/* size of first bucket */		bucket = 1;#endif		n = -(sizeof (*op) + RSLOP);	} else {		amt = pagesz;		bucket = pagebucket;	}	while (nbytes > amt + n) {		amt <<= 1;		if (amt == 0)			return (NULL);		bucket++;	}	/*	 * If nothing in hash bucket right now,	 * request more memory from the system.	 */  	if ((op = nextf[bucket]) == NULL) {  		morecore(bucket);  		if ((op = nextf[bucket]) == NULL)  			return (NULL);	}	/* remove from linked list */  	nextf[bucket] = op->ov_next;	op->ov_magic = MAGIC;	op->ov_index = bucket;  	nmalloc[bucket]++;#ifdef RCHECK	/*	 * Record allocated size of block and	 * bound space with magic numbers.	 */	op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1);	op->ov_rmagic = RMAGIC;  	*(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;#endif  	return ((char *)(op + 1));}/* * Allocate more memory to the indicated bucket. */morecore(bucket)	int bucket;{  	register union overhead *op;	register int sz;		/* size of desired block */  	int amt;			/* amount to allocate */  	int nblks;			/* how many blocks we get */	/*	 * sbrk_size <= 0 only for big, FLUFFY, requests (about	 * 2^30 bytes on a VAX, I think) or for a negative arg.	 */	sz = 1 << (bucket + 3);#ifdef DEBUG	ASSERT(sz > 0);#else	if (sz <= 0)		return;#endif	if (sz < pagesz) {		amt = pagesz;  		nblks = amt / sz;	} else {		amt = sz + pagesz;		nblks = 1;	}	op = (union overhead *)sbrk(amt);	/* no more room! */  	if ((int)op == -1)  		return;	/*	 * Add new memory allocated to that on	 * free list for this hash bucket.	 */  	nextf[bucket] = op;  	while (--nblks > 0) {		op->ov_next = (union overhead *)((caddr_t)op + sz);		op = (union overhead *)((caddr_t)op + sz);  	}}free(cp)	char *cp;{     	register int size;	register union overhead *op;  	if (cp == NULL)  		return;	op = (union overhead *)((caddr_t)cp - sizeof (union overhead));	/* 	 * The following botch is because csh tries to free a free block	 * when processing the =~ or !~ operators. -- layer@ucbmonet	*/#ifdef CSHbotch /* was DEBUG */  	ASSERT(op->ov_magic == MAGIC);		/* make sure it was in use */#else	if (op->ov_magic != MAGIC)		return;				/* sanity */#endif#ifdef RCHECK  	ASSERT(op->ov_rmagic == RMAGIC);	ASSERT(*(u_short *)((caddr_t)(op + 1) + op->ov_size) == RMAGIC);#endif  	size = op->ov_index;  	ASSERT(size < NBUCKETS);	op->ov_next = nextf[size];	/* also clobbers ov_magic */  	nextf[size] = op;  	nmalloc[size]--;}/* * When a program attempts "storage compaction" as mentioned in the * old malloc man page, it realloc's an already freed block.  Usually * this is the last block it freed; occasionally it might be farther * back.  We have to search all the free lists for the block in order * to determine its bucket: 1st we make one pass thru the lists * checking only the first block in each; if that fails we search * ``realloc_srchlen'' blocks in each list for a match (the variable * is extern so the caller can modify it).  If that fails we just copy * however many bytes was given to realloc() and hope it's not huge. */int realloc_srchlen = 4;	/* 4 should be plenty, -1 =>'s whole list */char *realloc(cp, nbytes)	char *cp; 	unsigned nbytes;{     	register u_int onb, i;	union overhead *op;  	char *res;	int was_alloced = 0;  	if (cp == NULL)  		return (malloc(nbytes));	op = (union overhead *)((caddr_t)cp - sizeof (union overhead));	if (op->ov_magic == MAGIC) {		was_alloced++;		i = op->ov_index;	} else {		/*		 * Already free, doing "compaction".		 *		 * Search for the old block of memory on the		 * free list.  First, check the most common		 * case (last element free'd), then (this failing)		 * the last ``realloc_srchlen'' items free'd.		 * If all lookups fail, then assume the size of		 * the memory block being realloc'd is the		 * largest possible (so that all "nbytes" of new		 * memory are copied into).  Note that this could cause		 * a memory fault if the old area was tiny, and the moon		 * is gibbous.  However, that is very unlikely.		 */		if ((int)(i = findbucket(op, 1)) < 0 &&		    (int)(i = findbucket(op, realloc_srchlen)) < 0)			i = NBUCKETS;	}	onb = 1 << (i + 3);	if (onb < pagesz)		onb -= sizeof (*op) + RSLOP;	else		onb += pagesz - sizeof (*op) - RSLOP;	/* avoid the copy if same size block */	if (was_alloced) {		if (i) {			i = 1 << (i + 2);			if (i < pagesz)				i -= sizeof (*op) + RSLOP;			else				i += pagesz - sizeof (*op) - RSLOP;		}		if (nbytes <= onb && nbytes > i) {#ifdef RCHECK			op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1);			*(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;#endif			return(cp);		} else			free(cp);	}  	if ((res = malloc(nbytes)) == NULL)  		return (NULL);  	if (cp != res)		/* common optimization if "compacting" */		bcopy(cp, res, (nbytes < onb) ? nbytes : onb);  	return (res);}/* * Search ``srchlen'' elements of each free list for a block whose * header starts at ``freep''.  If srchlen is -1 search the whole list. * Return bucket number, or -1 if not found. */staticfindbucket(freep, srchlen)	union overhead *freep;	int srchlen;{	register union overhead *p;	register int i, j;	for (i = 0; i < NBUCKETS; i++) {		j = 0;		for (p = nextf[i]; p && j != srchlen; p = p->ov_next) {			if (p == freep)				return (i);			j++;		}	}	return (-1);}/* * mstats - print out statistics about malloc *  * Prints two lines of numbers, one showing the length of the free list * for each size category, the second showing the number of mallocs - * frees for each size category. */showall(s)char **s;{	register int i, j;	register union overhead *p;	int totfree = 0,	totused = 0;	if (s[1])		/* 001 RNF */		csh_printf("Memory allocation statistics %s\nfree:", s[1]);	for (i = 0; i < NBUCKETS; i++) {		for (j = 0, p = nextf[i]; p; p = p->ov_next, j++)			;		if (s[1])			csh_printf(" %d", j);		/* 001 RNF */		totfree += j * (1 << (i + 3));	}	if (s[1])		csh_printf("\nused:");			/* 001 RNF */	for (i = 0; i < NBUCKETS; i++) {		if (s[1])			csh_printf(" %d", nmalloc[i]);	/* 001 RNF */		totused += nmalloc[i] * (1 << (i + 3));	}	if (s[1])		csh_printf("\n");			/* 001 RNF */	csh_printf("Total in use: %d, total free: %d\n", totused, totfree);}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?