P8000/WEGA/contrib/lcc/lib/libc/u8k/gen/malloc.c

280 lines
6.3 KiB
C

/* C storage allocator
* circular first-fit strategy
* works with noncontiguous, but monotonically linked, arena
* each block is preceded by a ptr to the (pointer of)
* the next following block
* blocks are exact number of words long
* aligned to the data type requirements of ALIGN
* pointers to blocks must have BUSY bit 0
* bit in ptr is 1 for busy, 0 for idle
* gaps in arena are merely noted as busy blocks
* last block of arena (pointed to by alloct) is empty and
* has a pointer to first
* idle blocks are coalesced during space search
*
* a different implementation may need to redefine
* ALIGN, NALIGN, BLOCK, BUSY, INT
* where INT is integer type to which a pointer can be cast
*/
#define INT long
#define ALIGN long
#define NALIGN 1
#define WORD sizeof(union store)
#define BLOCK 2048 /* a multiple of WORD*/
#define BUSY 1
#define testbusy(p) ((unsigned)(p)&BUSY)
#define setbusy(p) (union store *)(((INT)(p))|BUSY)
#define clearbusy(p) (union store *)((INT)(p)&~BUSY)
union store {
union store *ptr;
ALIGN dummy[NALIGN];
int calloc; /*calloc clears an array of integers*/
char c[4];
};
extern union store *ssgbrk();
extern union store *mkseg();
static union store newseg; /*pointer into new segment*/
static union store allocs[2]; /*initial arena*/
static union store *allocp; /*search ptr*/
static union store *alloct; /*arena top*/
static union store *allocx; /* for saving overwritten INT */
static int Lw48; /* != 0 if alloct points to real last block */
char *
malloc(nbytes)
unsigned nbytes;
{
register union store *p, *q;
unsigned nw;
int i = 0; /* 1, wenn noch ein INT fuer letzten */
/* (Null Block)-Pointer benoetigt wird */
unsigned j;
union store *P; /* hier neuen Speicher anhaengen */
union store *T;
if (nbytes > 0xfff8)
return(0); /* 8 Bytes aus 64KB Segment fuer *
/* ersten und letzten Zeiger */
if (!allocp || !Lw48)
/* noch kein echter Null-Block fuer alloct da */
i++;
if (!allocp)
{
allocp = &allocs[0];
alloct = &allocs[1];
allocs[0].ptr = setbusy(&allocs[1]);
allocs[1].ptr = setbusy(&allocs[0]);
newseg.ptr = mkseg(0, 0);
}
nw = (nbytes + WORD + (WORD -1)) / WORD; /* no of items */
/* to allocate */
p = allocp;
q = clearbusy(p->ptr);
/* if p points to free block, then (q-p)-1 == no of free items */
P = alloct;
/* if not enough free, append new block to block pointed to by P */
/* search first free block with at least nw elements */
/* idle blocks are coalesced during search space */
do
{
if (testbusy(p->ptr))
continue;
for (; !testbusy(q->ptr); )
{
/* Nachfolgeblock ist auch frei, */
/* deshalb an p-Block anhaengen */
/* da jetzt q-Block vernichtet werden wird, */
/* muss evtl allocp neu eingerichtet werden */
T = q;
q = clearbusy(q->ptr);
p->ptr = q; /* hier erfolgt die Vereinigung */
if (T == allocp)
allocp = q;
}
/* q zeigt nun auf ersten belegten Block */
/* p zeigt nach wie vor auf freien Block, der auf */
/* den q-Block weist */
if (q >= p + nw)
/* ohne wrap around waere p gross genug */
if ( p <= p + nw)
goto found; /* tatsaechlich gefunden */
if (q == alloct)
/* Ende allen verwalteten Speichers erreicht */
/* An Block auf den P weist, evtl. zusaetzlichen */
/* anfuegen */
P = p;
}
while (p = q, q = clearbusy(p->ptr), p!= allocp) ;
/* dieses p ist abgehandelt, naechstes nehmen */
/* nicht genuegend Speicher vorhanden, einen grossen Hieb holen */
j = ((((long)(nw+i-(alloct-P)))*WORD)+(BLOCK-1))/BLOCK;
/* no of requested (+i) - no of already available items rounded */
/* to BLOCKs (only 32 BLOCKs in one Segment !) */
if (j > 32)
return(0);
nbytes = (j * BLOCK) - 1;
p = ssgbrk(newseg.c[0], nbytes);
if ((long)p == -1L)
{
j = (((long)(nw+1))*WORD + (BLOCK-1))/BLOCK;
/* 1 item fuer alloct block schon beruecksichtigt */
nbytes = j * BLOCK;
p = mkseg(0, nbytes - 1);
if ((unsigned)p == -1)
return(0);
newseg.ptr = p;
i = 1; /* alloct block erforderlich */
}
if (i)
{
/* bisherigen alloct block (dummy) dicht machen */
/* und vor neu erhaltenen block ketten */
alloct->ptr = setbusy(p);
q = p;
Lw48++;
}
else
{
p = P;
q = alloct;
}
q = (union store *)((char *)q + j*BLOCK);
if (i)
q--;
q->ptr = setbusy(&allocs[0]);
alloct = q;
found:
allocp = p + nw;
if (q > allocp)
{
allocx = allocp->ptr;
allocp->ptr = q;
}
p->ptr = setbusy(allocp);
return((char *)(p+1));
}
free(ap)
register union store *ap;
{
allocp = --ap; /* strategy tuned for LIFO allocation */
ap->ptr = clearbusy(ap->ptr);
}
static char *
find_nc_block(nc)
unsigned nc;
{
register union store *p, *q;
unsigned wc;
wc = (nc + WORD + (WORD-1)) / WORD;
p = allocp;
q = clearbusy(p->ptr);
do
{
if (testbusy(p->ptr))
continue;
while (!testbusy(q->ptr))
{
if (q == allocp)
{
q = q->ptr;
allocp = q;
} else
q = q->ptr;
p->ptr = q;
}
if (q < p+wc)
continue;
if (p <= p+wc)
return((char *)p);
} while (p=q, q=clearbusy(p->ptr), p!=allocp) ;
return(0);
}
char *
realloc(p, nbytes)
register union store *p;
unsigned nbytes;
{
register union store *q;
union store *X, *Y;
unsigned own;
int i;
X = (p-1)->ptr;
if (!testbusy(X))
return((char *)0);
X = clearbusy(X);
Y = X->ptr;
free(p);
own = (char *)X - (char *)p;
/* size of old block */
q = (union store *)malloc(nbytes);
if (q == p)
return((char *)q);
if ((long)q == 0)
{
X->ptr = Y;
Y = p - 1;
Y->ptr = setbusy(X);
for (q=allocs; q != alloct; q=p)
{
p = clearbusy(q->ptr);
if (p == Y)
return((char *)0);
if ( p > Y)
{
q->ptr = setbusy(Y);
break;
}
}
return((char *)0);
}
nbytes = ((nbytes + WORD - 1) / WORD) * WORD;
/* size of new block */
i = (nbytes < own) ? nbytes : own;
q = (union store *)((char *)q + i);
p = (union store *)((char *)p + i);
i /= WORD;
while (i--)
{
p--;
q--;
*((INT *)q) = *(INT *)p;
}
if((char *)q+nbytes > (char *)p && (char *)q+nbytes < (char *)p+own)
((union store *)((char *)q+((char *)q+nbytes-(char *)p)))->ptr
= allocx;
return((char *)q);
}
/*
* calloc - allocate and clear memory block
*/
char *
calloc(num, size)
register unsigned num;
register unsigned size;
{
register INT *q;
num *= size;
q = (INT *)(malloc(num));
if((INT)q == 0)
return((char *)0);
num = ((num+WORD-1)/WORD)*WORD;
q = (INT *)((char *)q + num);
num /= WORD;
while((int)(--num) >= 0)
*--q = 0;
return((char *)q);
}