home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
HAM Radio 3
/
hamradioversion3.0examsandprograms1992.iso
/
misc
/
9q920411
/
alloc.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-04-10
|
10KB
|
407 lines
/* memory allocation routines
* Copyright 1991 Phil Karn, KA9Q
*
* 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 <alloc.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 unsigned long Intalloc; /* Calls to malloc with ints disabled */
static unsigned long Intfree; /* Calls to free with ints disabled */
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 unsigned long Sizes[16];
static int dostat __ARGS((int argc,char *argv[],void *p));
static int dofreelist __ARGS((int argc,char *argv[],void *p));
static int doibufsize __ARGS((int argc,char *argv[],void *p));
static int donibufs __ARGS((int argc,char *argv[],void *p));
static int dothresh __ARGS((int argc,char *argv[],void *p));
static int dosizes __ARGS((int argc,char *argv[],void *p));
struct cmds Memcmds[] = {
"freelist", dofreelist, 0, 0, NULLCHAR,
"ibufsize", doibufsize, 0, 0, NULLCHAR,
"nibufs", donibufs, 0, 0, NULLCHAR,
"sizes", dosizes, 0, 0, NULLCHAR,
"status", dostat, 0, 0, NULLCHAR,
"thresh", dothresh, 0, 0, NULLCHAR,
NULLCHAR,
};
#ifdef LARGEDATA
#define HUGE huge
#else
#define HUGE
#endif
union header {
struct {
union header HUGE *ptr;
unsigned long size;
} s;
long l[2];
};
typedef union header HEADER;
#define NULLHDR (HEADER HUGE *)NULL
#define ABLKSIZE (sizeof (HEADER))
static HEADER HUGE *morecore __ARGS((unsigned nu));
static HEADER Base;
static HEADER HUGE *Allocp = NULLHDR;
static unsigned long Heapsize;
/* Allocate block of 'nb' bytes */
void *
malloc(nb)
unsigned nb;
{
register HEADER HUGE *p, HUGE *q;
register unsigned nu;
int i;
if(!istate())
Intalloc++;
if(nb == 0)
return NULL;
/* Record the size of this request */
if((i = log2(nb)) >= 0)
Sizes[i]++;
/* Round up to full block, then add one for header */
nu = ((nb + ABLKSIZE - 1) / ABLKSIZE) + 1;
if((q = Allocp) == NULLHDR){
Base.s.ptr = Allocp = q = &Base;
Base.s.size = 1;
}
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 */
Allocs++;
Availmem -= p->s.size;
p++;
break;
}
if(p == Allocp && ((p = morecore(nu)) == NULLHDR)){
Memfail++;
break;
}
}
#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;
{
register char HUGE *cp;
register HEADER HUGE *up;
Morecores++;
if ((int)(cp = (char HUGE *)sbrk(nu * ABLKSIZE)) == -1)
return NULLHDR;
up = (HEADER *)cp;
up->s.size = nu;
up->s.ptr = up; /* satisfy audit */
free((void *)(up + 1));
Heapsize += nu*ABLKSIZE;
Frees--; /* Nullify increment inside free() */
return Allocp;
}
/* Put memory block back on heap */
void
free(blk)
void *blk;
{
register HEADER HUGE *p, HUGE *q;
unsigned short HUGE *ptr;
if(!istate())
Intfree++;
if(blk == NULL)
return; /* Required by ANSI */
p = (HEADER HUGE *)blk - 1;
/* Audit check */
if(p->s.ptr != p){
ptr = (unsigned short *)&blk;
printf("free: WARNING! invalid pointer (0x%lx) proc %s\n",
ptol(blk),Curproc->name);
stktrace();
Invalid++;
log(-1,"free: WARNING! invalid pointer (0x%lx) pc = 0x%x %x proc %s\n",
ptol(blk),ptr[-1],ptr[-2],Curproc->name);
return;
}
Availmem += p->s.size;
/* 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;
} 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;
} else {
/* Link to end of this entry */
q->s.ptr = p;
}
#ifdef circular
Allocp = q;
#endif
Frees++;
if(Memwait != 0)
psignal(&Memwait,0);
}
#ifdef notdef /* Not presently used */
/* Move existing block to new area */
void *
realloc(area,size)
void *area;
unsigned size;
{
unsigned osize;
HEADER HUGE *hp;
char HUGE *cp;
hp = ((HEADER *)area) - 1;
osize = (hp->s.size -1) * ABLKSIZE;
free(area);
if((cp = malloc(size)) != NULL && cp != area)
memcpy((char *)cp,(char *)area,size>osize? osize : size);
return cp;
}
#endif
/* Allocate block of cleared memory */
void *
calloc(nelem,size)
unsigned nelem; /* Number of elements */
unsigned 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)
unsigned nb;
{
register void *p;
while((p = malloc(nb)) == NULL){
Memwait++;
pwait(&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 available memory on our heap plus available system memory */
unsigned long
availmem()
{
return Availmem * ABLKSIZE + coreleft();
}
/* Print heap stats */
static int
dostat(argc,argv,envp)
int argc;
char *argv[];
void *envp;
{
tprintf("heap size %lu avail %lu (%lu%%) morecores %lu coreleft %lu\n",
Heapsize,Availmem * ABLKSIZE,100L*Availmem*ABLKSIZE/Heapsize,
Morecores,coreleft());
tprintf("allocs %lu frees %lu (diff %lu) alloc fails %lu invalid frees %lu\n",
Allocs,Frees,Allocs-Frees,Memfail,Invalid);
tprintf("interrupts-off calls to malloc %lu free %lu\n",Intalloc,Intfree);
tprintf("garbage collections yellow %lu red %lu\n",Yellows,Reds);
iqstat();
return 0;
}
/* Print heap free list */
static int
dofreelist(argc,argv,envp)
int argc;
char *argv[];
void *envp;
{
HEADER HUGE *p;
int i = 0;
for(p = Base.s.ptr;p != &Base;p = p->s.ptr){
tprintf("%5lx %6lu",ptol((void *)p),p->s.size * ABLKSIZE);
if(++i == 4){
i = 0;
if(tprintf("\n") == EOF)
return 0;
} else
tprintf(" | ");
}
if(i != 0)
tprintf("\n");
return 0;
}
static int
dosizes(argc,argv,p)
int argc;
char *argv[];
void *p;
{
int i;
for(i=0;i<16;i += 4){
tprintf("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]);
}
return 0;
}
int
domem(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return subcmd(Memcmds,argc,argv,p);
}
static int
donibufs(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return setint(&Nibufs,"Interrupt pool buffers",argc,argv);
}
static int
doibufsize(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return setuns(&Ibufsize,"Interrupt buffer size",argc,argv);
}
static int
dothresh(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return setlong(&Memthresh,"Free memory threshold (bytes)",argc,argv);
}
/* 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 red;
for(;;){
pause(1000L); /* Run every second */
/* If memory is low, collect some garbage. If memory is VERY
* low, invoke the garbage collection routines in "red" mode.
*/
if(availmem() < Memthresh){
if(availmem() < Memthresh/2){
red = 1;
Reds++;
} else {
red = 0;
Yellows++;
}
for(fp = Gcollect;*fp != NULL;fp++)
(**fp)(red);
}
}
}