⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 alloc.c

📁 在51单片机上实现TCPIP协议栈
💻 C
字号:
/* memory allocation routines
 *
 * Adapted from alloc routine in K&R; memory statistics and interrupt
 * protection added for use with net package. Must be used in place of
 * standard Turbo-C library routines because the latter check for stack/heap
 * collisions. This causes erroneous failures because process stacks are
 * allocated off the heap.
 */

#include <stdio.h>
#include <dos.h>
#include "global.h"
#include "mbuf.h"
#include "proc.h"
#include "cmdparse.h"

static unsigned long Memfail;	/* Count of allocation failures */
static unsigned long Allocs;	/* Total allocations */
static unsigned long Frees;	/* Total frees */
static unsigned long Invalid;	/* Total calls to free with garbage arg */
static int Memwait;		/* Number of tasks waiting for memory */
static unsigned long Yellows;	/* Yellow alert garbage collections */
static unsigned long Reds;	/* Red alert garbage collections */
unsigned long Availmem;		/* Heap memory, ABLKSIZE units */
static unsigned long Morecores;
static int Memdebug;
static unsigned long Sizes[16];

/* This debugging pattern MUST be exactly equal in size to the "header"
 * union defined later
 */
static char Debugpat[] = { 0xfe,0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef };

static int domdebug(int argc,char *argv[],void *ptr);
static int dostat(int argc,char *argv[],void *p);
static int dofreelist(int argc,char *argv[],void *p);
static int dothresh(int argc,char *argv[],void *p);
static int dosizes(int argc,char *argv[],void *p);

struct cmds Memcmds[] = {
	"debug",	domdebug,	0, 0, NULL,
	"freelist",	dofreelist,	0, 0, NULL,
	"sizes",	dosizes,	0, 0, NULL,
	"status",	dostat,		0, 0, NULL,
	"thresh",	dothresh,	0, 0, NULL,
	NULL,
};

#ifdef	LARGEDATA
#define	HUGE	huge
#else
#define	HUGE
#endif

union header {
	struct {
		union header HUGE *ptr;
		unsigned long size;
	} s;
	char c[8];	/* For debugging; also ensure size is 8 bytes */
};

typedef union header HEADER;

#define	ABLKSIZE	(sizeof (HEADER))
#define	BTOU(nb)	((((nb) + ABLKSIZE - 1) / ABLKSIZE) + 1)

static HEADER HUGE *morecore(unsigned nu);

static HEADER Base;
static HEADER HUGE *Allocp = NULL;
static unsigned long Heapsize;


/* Memory blocks obtained from MS-DOS by allocmem() call */
struct sysblock {
	unsigned seg;
	unsigned npar;
};
#define	NSYSBLOCK	5
struct sysblock Sysblock[NSYSBLOCK];

/* Allocate block of 'nb' bytes */
void *
malloc(nb)
size_t nb;
{
	int i;
	int i_state;
	register HEADER HUGE *p, HUGE *q;
	register unsigned nu;

	if(nb == 0)
		return NULL;

	Allocs++;
	/* Record the size of this request */
	if((i = ilog2(nb)) >= 0)
		Sizes[i]++;
	
	/* Round up to full block, then add one for header */
	nu = BTOU(nb);

	i_state = dirps();
	/* Initialize heap pointers if necessary */
	if((q = Allocp) == NULL){
		Base.s.ptr = Allocp = q = &Base;
		Base.s.size = 1;
	}
	/* Search heap list */
	for(p = q->s.ptr; ; q = p, p = p->s.ptr){
		if(p->s.size >= nu){
			/* This chunk is at least as large as we need */
			if(p->s.size <= nu + 1){
				/* This is either a perfect fit (size == nu)
				 * or the free chunk is just one unit larger.
				 * In either case, alloc the whole thing,
				 * because there's no point in keeping a free
				 * block only large enough to hold the header.
				 */
				q->s.ptr = p->s.ptr;
			} else {
				/* Carve out piece from end of entry */
				p->s.size -= nu;
				p += p->s.size;
				p->s.size = nu;
			}
#ifdef	circular
			Allocp = q;
#endif
			p->s.ptr = p;	/* for auditing */
			Availmem -= p->s.size;
			p++;
			break;
		}
		/* We've searched all the way around the list without
		 * finding anything. Try to get more core from the system,
		 * unless we're in an interrupt handler
		 */
		if(p == Allocp && (!i_state || (p = morecore(nu)) == NULL)){
			p = NULL;
			Memfail++;
			break;
		}
	}
	restore(i_state);
#ifdef	LARGEDATA
	/* On the brain-damaged Intel CPUs in "large data" model,
	 * make sure the pointer's offset field isn't null
	 * (unless the entire pointer is null).
	 * The Turbo C compiler and certain
	 * library functions like strrchr() assume this.
	 */
	if(FP_OFF(p) == 0 && FP_SEG(p) != 0){
		/* Return denormalized but equivalent pointer */
		return (void *)MK_FP(FP_SEG(p)-1,16);
	}
#endif
	return (void *)p;
}
/* Get more memory from the system and put it on the heap */
static HEADER HUGE *
morecore(nu)
unsigned nu;
{
	char HUGE *cp;
	HEADER HUGE *up;
	unsigned size;
	unsigned segp;
	unsigned npar;
	struct sysblock *sp;
	int i;
	void *sbrk(int);	/***/

	Morecores++;
	size = nu * ABLKSIZE;
	/* First try to expand our main memory block */
	if((int)(cp = (char HUGE *)sbrk(size)) != -1){
		up = (HEADER *)cp;
		up->s.size = nu;
		up->s.ptr = up;	/* satisfy audit */
		free(up + 1);
		Heapsize += size;
		Frees--;	/* Nullify increment inside free() */
		return Allocp;
	}
#ifndef	__GNUC__
	/* That failed; the main memory block must have grown into another
	 * allocated block, or something else (e.g., the increase handles
	 * call in ioinit()) must have allocated memory just beyond it.
	 * Allocate or extend an additional memory block.
	 */
	npar = (size+16)/16;	/* Convert size from bytes to paragraphs */
	cp = NULL;
	for(sp=Sysblock,i=0;i < NSYSBLOCK;i++,sp++){
		if(sp->npar != 0){
			/* Try to expand this block */
			if(setblock(sp->seg,sp->npar + npar) != -1){
				/* Failed (-1 == SUCCESS; strange!) */
				continue;
			}
			/* Block expansion succeeded */
			cp = MK_FP(sp->seg + sp->npar,0);
			sp->npar += npar;
		} else {
			/* Allocate new block */
			if(allocmem(npar,&segp) != -1){
				return NULL;	/* Complete failure */
			}
			/* -1 indicates SUCCESS (strange) */
			sp->seg = segp;
			sp->npar = npar;
			cp = MK_FP(segp,0);
		}
		break;
	}
	if(cp != (char HUGE *)NULL){
		/* Expand or create succeeded, add to heap */
		up = (HEADER *)cp;
		up->s.size = (npar*16)/ABLKSIZE;
		up->s.ptr = up;	/* satisfy audit */
		free(up + 1);
		Heapsize += npar*16;
		Frees--;	/* Nullify increment inside free() */
		return Allocp;
	}
#endif	/* __GNUC__ */
	return NULL;
}

/* Put memory block back on heap */
void
free(blk)
void *blk;
{
	register HEADER HUGE *p, HUGE *q;
	unsigned short HUGE *ptr;
	int i_state;
	int i;

	if(blk == NULL)
		return;		/* Required by ANSI */
	Frees++;
	p = ((HEADER HUGE *)blk) - 1;
	/* Audit check */
	if(p->s.ptr != p){
		Invalid++;
		if(istate()){
			ptr = (unsigned short *)&blk;
			printf("free: WARNING! invalid pointer (%p) proc %s\n",
			 blk,Curproc->name);
			stktrace();

			logmsg(-1,"free: WARNING! invalid pointer (%p) pc = 0x%x %x proc %s\n",
			 blk,ptr[-1],ptr[-2],Curproc->name);
		}
		return;
	}
	Availmem += p->s.size;
	if(Memdebug){
		/* Fill data area with pattern to detect later overwrites */
		for(i=1;i<p->s.size;i++){
			memcpy(p[i].c,Debugpat,sizeof(Debugpat));
		}
	}
	i_state = dirps();
 	/* Search the free list looking for the right place to insert */
	for(q = Allocp; !(p > q && p < q->s.ptr); q = q->s.ptr){
		/* Highest address on circular list? */
		if(q >= q->s.ptr && (p > q || p < q->s.ptr))
			break;
	}
	if(p + p->s.size == q->s.ptr){
		/* Combine with front of this entry */
		p->s.size += q->s.ptr->s.size;
		p->s.ptr = q->s.ptr->s.ptr;
		if(Memdebug){
			memcpy(q->s.ptr->c,Debugpat,sizeof(Debugpat));
		}
	} else {
		/* Link to front of this entry */
		p->s.ptr = q->s.ptr;
	}
	if(q + q->s.size == p){
		/* Combine with end of this entry */
		q->s.size += p->s.size;
		q->s.ptr = p->s.ptr;
		if(Memdebug){
			memcpy(p->c,Debugpat,sizeof(Debugpat));
		}
	} else {
		/* Link to end of this entry */
		q->s.ptr = p;
	}
#ifdef	circular
	Allocp = q;
#endif
	restore(i_state);
	if(Memwait != 0)
		ksignal(&Memwait,0);
}

/* Move existing block to new area */
void *
realloc(area,size)
void *area;
size_t size;
{
	unsigned osize;
	HEADER HUGE *hp;
	void *new;

	hp = ((HEADER *)area) - 1;
	osize = (hp->s.size -1) * ABLKSIZE;

	/* We must copy the block since freeing it may cause the heap
	 * debugging code to scribble over it.
	 */
	if((new = malloc(size)) != NULL)
		memcpy(new,area,size>osize? osize : size);
	free(area);
	return new;
}

/* Allocate block of cleared memory */
void *
calloc(nelem,size)
size_t nelem;	/* Number of elements */
size_t size;	/* Size of each element */
{
	register unsigned i;
	register char *cp;

	i = nelem * size;
	if((cp = malloc(i)) != NULL)
		memset(cp,0,i);
	return cp;
}
/* Version of malloc() that waits if necessary for memory to become available */
void *
mallocw(nb)
size_t nb;
{
	register void *p;

	while((p = malloc(nb)) == NULL){
		Memwait++;
		kwait(&Memwait);
		Memwait--;
	}
	return p;
}
/* Version of calloc that waits if necessary for memory to become available */
void *
callocw(nelem,size)
unsigned nelem;	/* Number of elements */
unsigned size;	/* Size of each element */
{
	register unsigned i;
	register char *cp;

	i = nelem * size;
	cp = mallocw(i);
	memset(cp,0,i);
	return cp;
}
/* Return 0 if at least Memthresh memory is available. Return 1 if
 * less than Memthresh but more than Memthresh/2 is available; i.e.,
 * if a yellow garbage collection should be performed. Return 2 if
 * less than Memthresh/2 is available, i.e., a red collection should
 * be performed.
 */
int
availmem()
{
	void *p;

	if(Availmem*ABLKSIZE >= Memthresh)
		return 0;	/* We're clearly OK */

	/* There's not enough on the heap; try calling malloc to see if
	 * it can get more from the system
	 */
	if((p = malloc(Memthresh)) != NULL){
		free(p);
		return 0;	/* Okay */
	}
	if((p = malloc(Memthresh/2)) != NULL){
		free(p);
		return 1;	/* Yellow alert */
	}
	return 2;		/* Red alert */
}

/* Print heap stats */
static int
dostat(argc,argv,envp)
int argc;
char *argv[];
void *envp;
{
	struct sysblock *sp;
	int i;

	printf("heap size %lu avail %lu (%lu%%) morecores %lu\n",
	 Heapsize,Availmem * ABLKSIZE,100L*Availmem*ABLKSIZE/Heapsize,
	 Morecores);
	if(Sysblock[0].npar != 0){
		printf("Extra blocks:");
		for(i=0,sp=Sysblock;i< NSYSBLOCK;i++,sp++){
			if(sp->npar == 0)
				break;
			printf(" (%x0-%x0)",sp->seg,sp->seg+sp->npar);
		}
		printf("\n");
	}
	printf("allocs %lu frees %lu (diff %lu) alloc fails %lu invalid frees %lu\n",
		Allocs,Frees,Allocs-Frees,Memfail,Invalid);
	printf("garbage collections yellow %lu red %lu\n",Yellows,Reds);
	printf("\n");
	mbufstat();
	return 0;
}

/* Print heap free list */
static int
dofreelist(argc,argv,envp)
int argc;
char *argv[];
void *envp;
{
	HEADER HUGE *p;
	int i = 0;
	int j;
	unsigned corrupt;
	int i_state;

	for(p = Base.s.ptr;p != (HEADER HUGE *)&Base;p = p->s.ptr){
		corrupt = 0;
		if(Memdebug){
			i_state = dirps();
			for(j=1;j<p->s.size;j++){
				if(memcmp(p[j].c,Debugpat,sizeof(Debugpat)) != 0){
					corrupt = j;
					break;
				}
			}
			restore(i_state);
		}
		if(corrupt)
			printf("%p %6lu C: %u",p,p->s.size * ABLKSIZE,corrupt);
		else
			printf("%p %6lu",p,p->s.size * ABLKSIZE);

		if(++i == 4){
			i = 0;
			if(printf("\n") == EOF)
				return 0;
		} else
			printf(" | ");
	}
	if(i != 0)
		printf("\n");
	return 0;
}
static int
dosizes(argc,argv,p)
int argc;
char *argv[];
void *p;
{
	int i;

	for(i=0;i<16;i += 4){
		printf("N>=%5u:%7ld| N>=%5u:%7ld| N>=%5u:%7ld| N>=%5u:%7ld\n",
		 1<<i,Sizes[i],	2<<i,Sizes[i+1],
		 4<<i,Sizes[i+2],8<<i,Sizes[i+3]);
	}
	mbufsizes();
	return 0;
}
int
domem(argc,argv,p)
int argc;
char *argv[];
void *p;
{
	return subcmd(Memcmds,argc,argv,p);
}

static int
dothresh(argc,argv,p)
int argc;
char *argv[];
void *p;
{
	return setlong(&Memthresh,"Free memory threshold (bytes)",argc,argv);
}
static int
domdebug(argc,argv,ptr)
int argc;
char *argv[];
void *ptr;
{
	int prev,j,i_state;
	HEADER HUGE *p;

	prev = Memdebug;
	setbool(&Memdebug,"Heap debugging",argc,argv);
	if(prev == 1 || Memdebug == 0)
		return 0;

	/* Turning debugging on; reinitialize free areas to debug pattern */
	i_state = dirps();
	for(p = Base.s.ptr;p != (HEADER HUGE *)&Base;p = p->s.ptr){
		for(j=1;j<p->s.size;j++){
			memcpy(p[j].c,Debugpat,sizeof(Debugpat));
		}
	}
	restore(i_state);
	return 0;
}

/* Background memory compactor, used when memory runs low */
void
gcollect(i,v1,v2)
int i;	/* Args not used */
void *v1;
void *v2;
{
	void (**fp)(int);
	int red;

	for(;;){
		ppause(1000L);	/* Run every second */
		/* If memory is low, collect some garbage. If memory is VERY
		 * low, invoke the garbage collection routines in "red" mode.
		 */
		switch(availmem()){
		case 0:
			continue;	/* All is well */
		case 1:
			red = 0;
			Yellows++;
			break;
		case 2:
			red = 1;
			Reds++;
			break;
		}
		for(fp = Gcollect;*fp != NULL;fp++)
			(**fp)(red);
	}
}

⌨️ 快捷键说明

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