mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
355 lines
9.4 KiB
355 lines
9.4 KiB
/*
|
|
*
|
|
* Copyright 1994 FirmWorks, Mountain View CA USA. All rights reserved.
|
|
* Copyright (c) 1995 FirePower Systems, Inc.
|
|
*
|
|
* $RCSfile: vrmalloc.c $
|
|
* $Revision: 1.6 $
|
|
* $Date: 1996/02/17 00:41:29 $
|
|
* $Locker: $
|
|
*
|
|
*
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
* A "smarter" malloc William L. Sebok
|
|
* Sept. 24, 1984
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
* If n = the size of an area rounded DOWN to the nearest power of two,
|
|
* all free areas of memory whose length is the same index n is organized
|
|
* into a chain with other free areas of index n. A request for memory
|
|
* takes the first item in the chain whose index is the size of the
|
|
* request rounded UP to the nearest power of two. If this chain is
|
|
* empty the next higher chain is examined. If no larger chain has memory
|
|
* then new memory is allocated. Only the amount of new memory needed is
|
|
* allocated. Any old free memory left after an allocation is returned
|
|
* to the free list. Extra new memory returned because of rounding
|
|
* to page boundaries is returned to free list.
|
|
*
|
|
* All memory areas (free or busy) handled by malloc are also chained
|
|
* sequentially by increasing address. When memory is freed it is
|
|
* merged with adjacent free areas, if any. If a free area of memory
|
|
* ends at the end of memory (i.e. at the break), the break is
|
|
* contracted, freeing the memory back to the system.
|
|
*
|
|
* Notes:
|
|
* ov_length field includes sizeof(struct overhead)
|
|
* adjacency chain includes all memory, allocated plus free.
|
|
*/
|
|
|
|
#include "veneer.h"
|
|
|
|
#define MAGIC_FREE 0x548a934c
|
|
#define MAGIC_BUSY 0xc139569a
|
|
|
|
#define NBUCKETS 24
|
|
#define NALIGN 4
|
|
|
|
struct qelem {
|
|
struct qelem *q_forw;
|
|
struct qelem *q_back;
|
|
};
|
|
|
|
struct overhead {
|
|
struct qelem ov_adj; /* adjacency chain pointers */
|
|
struct qelem ov_buk; /* bucket chain pointers */
|
|
long ov_magic;
|
|
unsigned long ov_length;
|
|
};
|
|
|
|
char endfree = 0;
|
|
struct qelem adjhead = { &adjhead, &adjhead };
|
|
struct qelem buckets[NBUCKETS] = {
|
|
&buckets[0], &buckets[0],
|
|
&buckets[1], &buckets[1],
|
|
&buckets[2], &buckets[2],
|
|
&buckets[3], &buckets[3],
|
|
&buckets[4], &buckets[4],
|
|
&buckets[5], &buckets[5],
|
|
&buckets[6], &buckets[6],
|
|
&buckets[7], &buckets[7],
|
|
&buckets[8], &buckets[8],
|
|
&buckets[9], &buckets[9],
|
|
&buckets[10], &buckets[10],
|
|
&buckets[11], &buckets[11],
|
|
&buckets[12], &buckets[12],
|
|
&buckets[13], &buckets[13],
|
|
&buckets[14], &buckets[14],
|
|
&buckets[15], &buckets[15],
|
|
&buckets[16], &buckets[16],
|
|
&buckets[17], &buckets[17],
|
|
&buckets[18], &buckets[18],
|
|
&buckets[19], &buckets[19],
|
|
&buckets[20], &buckets[20],
|
|
&buckets[21], &buckets[21],
|
|
&buckets[22], &buckets[22],
|
|
&buckets[23], &buckets[23],
|
|
};
|
|
|
|
/*
|
|
* The following macros depend on the order of the elements in struct overhead
|
|
*/
|
|
#define TOADJ(p) ((struct qelem *)(p))
|
|
#define FROMADJ(p) ((struct overhead *)(p))
|
|
#define FROMBUK(p) ((struct overhead *)( (char *)p - sizeof(struct qelem)))
|
|
#define TOBUK(p) ((struct qelem *)( (char *)p + sizeof(struct qelem)))
|
|
|
|
#ifndef CURBRK
|
|
#define CURBRK sbrk(0)
|
|
#endif CURBRK
|
|
|
|
STATIC void insque(), remque();
|
|
|
|
#ifdef NULL
|
|
#undef NULL
|
|
#endif
|
|
#define NULL 0
|
|
#ifdef debug
|
|
# define ASSERT(p,q) if (!(p)) fatal(q)
|
|
#else
|
|
# define ASSERT(p,q)
|
|
#endif
|
|
|
|
#define ALIGN(n, granule) ((n + ((granule)-1)) & ~((granule)-1))
|
|
|
|
char *
|
|
malloc(nbytes)
|
|
unsigned nbytes;
|
|
{
|
|
register struct overhead *p, *q;
|
|
register int surplus = 0;
|
|
register struct qelem *bucket;
|
|
nbytes = ALIGN(nbytes, NALIGN) + sizeof(struct overhead);
|
|
bucket = &buckets[log2(nbytes-1) + 1]; /* log2 rounded up */
|
|
for (p = NULL; bucket < &buckets[NBUCKETS]; bucket++) {
|
|
if (bucket->q_forw != bucket) {
|
|
/* remove from bucket chain */
|
|
p = FROMBUK(bucket->q_forw);
|
|
ASSERT(p->ov_magic == MAGIC_FREE, "\nmalloc: Entry \
|
|
not marked FREE found on Free List!\n");
|
|
remque(TOBUK(p));
|
|
surplus = p->ov_length - nbytes;
|
|
break;
|
|
}
|
|
}
|
|
if (p == NULL) {
|
|
#ifdef USE_SBRK
|
|
register int i;
|
|
p = (struct overhead *)CURBRK;
|
|
if ((int)p == -1) {
|
|
return(NULL);
|
|
}
|
|
if (i = (int)p&(NALIGN-1)) {
|
|
sbrk(NALIGN-i);
|
|
}
|
|
p = (struct overhead *)sbrk(nbytes);
|
|
if ((int)p == -1) {
|
|
return(NULL);
|
|
}
|
|
q = (struct overhead *)CURBRK;
|
|
if ((int)q == -1) {
|
|
return(NULL);
|
|
}
|
|
p->ov_length = (char *)q - (char *)p;
|
|
surplus = p->ov_length - nbytes;
|
|
/* add to end of adjacency chain */
|
|
ASSERT((FROMADJ(adjhead.q_back)) < p, "\nmalloc: Entry in \
|
|
adjacency chain found with address lower than Chain head!\n" );
|
|
insque(TOADJ(p),adjhead.q_back);
|
|
#else
|
|
struct qelem *pp;
|
|
int alloc_size = ALIGN(nbytes, PAGE_SIZE);
|
|
|
|
p = (struct overhead *)alloc(alloc_size, NALIGN);
|
|
if ((int)p == -1) {
|
|
return(NULL);
|
|
}
|
|
p->ov_length = alloc_size;
|
|
surplus = p->ov_length - nbytes;
|
|
|
|
/* add to adjacency chain in the correct place */
|
|
for (pp = adjhead.q_forw; pp != &adjhead; pp = pp->q_forw) {
|
|
if (p < FROMADJ(pp)) {
|
|
break;
|
|
}
|
|
}
|
|
ASSERT(pp == &adjhead || (p < FROMADJ(pp)),
|
|
"\nmalloc: Bogus insertion in adjacency list\n");
|
|
insque(TOADJ(p),pp->q_back);
|
|
#endif
|
|
}
|
|
if (surplus > sizeof(struct overhead)) {
|
|
/* if big enough, split it up */
|
|
q = (struct overhead *)( (char *)p + nbytes);
|
|
q->ov_length = surplus;
|
|
p->ov_length = nbytes;
|
|
q->ov_magic = MAGIC_FREE;
|
|
/* add surplus into adjacency chain */
|
|
insque(TOADJ(q),TOADJ(p));
|
|
/* add surplus into bucket chain */
|
|
insque(TOBUK(q),&buckets[log2(surplus)]);
|
|
}
|
|
p->ov_magic = MAGIC_BUSY;
|
|
return((char*)p + sizeof(struct overhead));
|
|
}
|
|
|
|
void
|
|
free(mem)
|
|
register char *mem;
|
|
{
|
|
register struct overhead *p, *q;
|
|
if (mem == NULL) {
|
|
return;
|
|
}
|
|
p = (struct overhead *)(mem - sizeof(struct overhead));
|
|
if (p->ov_magic == MAGIC_FREE) {
|
|
return;
|
|
}
|
|
if (p->ov_magic != MAGIC_BUSY) {
|
|
fatal("attempt to free memory not allocated with malloc!\n");
|
|
}
|
|
q = FROMADJ((TOADJ(p))->q_back);
|
|
if (q != FROMADJ(&adjhead)) { /* q is not the first list item */
|
|
ASSERT(q < p, "\nfree: While trying to merge a free area with \
|
|
a lower adjacent free area,\n addresses were found out of order!\n");
|
|
/* If lower segment can be merged */
|
|
if ((q->ov_magic == MAGIC_FREE) &&
|
|
((char *)q + q->ov_length == (char *)p) ) {
|
|
|
|
/* remove lower address area from bucket chain */
|
|
remque(TOBUK(q));
|
|
/* remove upper address area from adjacency chain */
|
|
remque(TOADJ(p));
|
|
q->ov_length += p->ov_length;
|
|
p->ov_magic = NULL;
|
|
p = q;
|
|
}
|
|
}
|
|
q = FROMADJ((TOADJ(p))->q_forw);
|
|
if (q != FROMADJ(&adjhead)) { /* q is not the last list item */
|
|
/* upper segment can be merged */
|
|
ASSERT(q > p, "\nfree: While trying to merge a free area with \
|
|
a higher adjacent free area,\n addresses were found out of order!\n");
|
|
if ( (q->ov_magic == MAGIC_FREE) &&
|
|
((char *)p + p->ov_length == (char *)q) ) {
|
|
|
|
/* remove upper from bucket chain */
|
|
remque(TOBUK(q));
|
|
/* remove upper from adjacency chain */
|
|
remque(TOADJ(q));
|
|
p->ov_length += q->ov_length;
|
|
q->ov_magic = NULL;
|
|
}
|
|
}
|
|
#ifdef USE_SBRK
|
|
/* freed area is at end of memory */
|
|
if ((endfree && adjhead.q_back == TOADJ(p)) &&
|
|
((char*)p + p->ov_length == (char *)CURBRK) ) {
|
|
|
|
/* remove from end of adjacency chain */
|
|
remque(adjhead.q_back);
|
|
/* release memory to system */
|
|
sbrk( -((int)(p->ov_length)));
|
|
return;
|
|
}
|
|
#endif
|
|
p->ov_magic = MAGIC_FREE;
|
|
/* place in bucket chain */
|
|
insque(TOBUK(p),&buckets[log2(p->ov_length)]);
|
|
return;
|
|
}
|
|
|
|
char *
|
|
realloc(mem,nbytes)
|
|
register char *mem; unsigned nbytes;
|
|
{
|
|
register char *newmem;
|
|
register struct overhead *p, *q;
|
|
register int surplus;
|
|
if (mem == NULL) {
|
|
return(malloc(nbytes));
|
|
}
|
|
if(mem > (char*)FROMADJ(adjhead.q_back) + sizeof(struct overhead)) {
|
|
return(NULL);
|
|
}
|
|
|
|
p = (struct overhead *)(mem - sizeof(struct overhead));
|
|
nbytes = (nbytes + (NALIGN-1)) & (~(NALIGN-1));
|
|
if ( (p->ov_magic == MAGIC_BUSY) && (q = FROMADJ(adjhead.q_back)) != p
|
|
&& (q->ov_magic != MAGIC_FREE || (FROMADJ(q->ov_adj.q_back) != p)) ) {
|
|
|
|
free(mem);
|
|
}
|
|
if( (p->ov_magic == MAGIC_BUSY || p->ov_magic == MAGIC_FREE)
|
|
&& (surplus = p->ov_length - nbytes - sizeof(struct overhead)) >= 0 ) {
|
|
if (surplus > sizeof(struct overhead)) {
|
|
/* return surplus to free list */
|
|
nbytes += sizeof(struct overhead);
|
|
#ifdef USE_SBRK
|
|
/* freed area is at end of memory */
|
|
if ( endfree && adjhead.q_back == TOADJ(p)
|
|
&& (char*)p + p->ov_length == (char *)CURBRK ) {
|
|
/* release memory to system */
|
|
sbrk(-surplus);
|
|
} else
|
|
#endif
|
|
{
|
|
q = (struct overhead *)( (char *)p + nbytes);
|
|
q->ov_length = surplus;
|
|
q->ov_magic = MAGIC_FREE;
|
|
insque(TOADJ(q),TOADJ(p));
|
|
insque(TOBUK(q),&buckets[log2(surplus)]);
|
|
}
|
|
p->ov_length = nbytes;
|
|
}
|
|
if (p->ov_magic == MAGIC_FREE) {
|
|
remque(TOBUK(p));
|
|
p->ov_magic = MAGIC_BUSY;
|
|
}
|
|
return(mem);
|
|
}
|
|
newmem = malloc(nbytes);
|
|
if (newmem != mem && newmem != NULL) {
|
|
register unsigned n;
|
|
if (p->ov_magic == MAGIC_BUSY || p->ov_magic == MAGIC_FREE) {
|
|
n = p->ov_length - sizeof(struct overhead);
|
|
nbytes = (nbytes < n) ? nbytes : n ;
|
|
}
|
|
bcopy(mem,newmem,nbytes);
|
|
}
|
|
if (p->ov_magic == MAGIC_BUSY) {
|
|
free(mem);
|
|
}
|
|
return(newmem);
|
|
}
|
|
|
|
log2(n)
|
|
register int n;
|
|
{
|
|
register int i = 0;
|
|
while ((n >>= 1) > 0) {
|
|
i++;
|
|
}
|
|
return(i);
|
|
}
|
|
|
|
void
|
|
insque(item,queu)
|
|
register struct qelem *item, *queu;
|
|
{
|
|
register struct qelem *pueu;
|
|
pueu = queu->q_forw;
|
|
item->q_forw = pueu;
|
|
item->q_back = queu;
|
|
queu->q_forw = item;
|
|
pueu->q_back = item;
|
|
}
|
|
|
|
void
|
|
remque(item)
|
|
register struct qelem *item;
|
|
{
|
|
register struct qelem *queu, *pueu;
|
|
pueu = item->q_forw;
|
|
queu = item->q_back;
|
|
queu->q_forw = pueu;
|
|
pueu->q_back = queu;
|
|
}
|