new malloc.c, derived from new Minix version
This commit is contained in:
parent
30208cda9a
commit
fec7208f70
|
@ -1,116 +1,185 @@
|
||||||
/* $Header$ */
|
/* replace undef by define */
|
||||||
|
#undef DEBUG /* check assertions */
|
||||||
|
#undef SLOWDEBUG /* some extra test loops (requires DEBUG) */
|
||||||
|
|
||||||
#define CLICK_SIZE 4096
|
#ifdef DEBUG
|
||||||
#if EM_WSIZE == EM_PSIZE
|
#define ASSERT(b) if (!(b)) assert_failed();
|
||||||
typedef unsigned int vir_bytes;
|
|
||||||
#else
|
#else
|
||||||
typedef long vir_bytes;
|
#define ASSERT(b) /* empty */
|
||||||
#endif
|
#endif
|
||||||
extern bcopy();
|
|
||||||
|
|
||||||
#define ALIGN(x, a) (((x) + (a - 1)) & ~(a - 1))
|
#ifdef EM_WSIZE == EM_PSIZE
|
||||||
#define BUSY 1
|
#define ptrint int
|
||||||
#define NEXT(p) (* (char **) (p))
|
|
||||||
|
|
||||||
#ifdef pdp
|
|
||||||
#define BUGFIX 64 /* cannot set break in top 64 bytes */
|
|
||||||
#else
|
#else
|
||||||
#define BUGFIX 0
|
#define ptrint long
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define BRKSIZE 4096
|
||||||
|
#define PTRSIZE sizeof(char *)
|
||||||
|
#define Align(x,a) (((x) + (a - 1)) & ~(a - 1))
|
||||||
|
#define NextSlot(p) (* (char **) ((p) - PTRSIZE))
|
||||||
|
#define NextFree(p) (* (char **) (p))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A short explanation of the data structure and algorithms.
|
||||||
|
* An area returned by malloc() is called a slot. Each slot
|
||||||
|
* contains the number of bytes requested, but preceeded by
|
||||||
|
* an extra pointer to the next the slot in memory.
|
||||||
|
* '_bottom' and '_top' point to the first/last slot.
|
||||||
|
* More memory is asked for using brk() and appended to top.
|
||||||
|
* The list of free slots is maintained to keep malloc() fast.
|
||||||
|
* '_empty' points the the first free slot. Free slots are
|
||||||
|
* linked together by a pointer at the start of the
|
||||||
|
* user visable part, so just after the next-slot pointer.
|
||||||
|
* Free slots are merged together by free().
|
||||||
|
*/
|
||||||
|
|
||||||
extern char *sbrk(), *brk();
|
extern char *sbrk(), *brk();
|
||||||
static char *bottom, *top;
|
static char *_bottom, *_top, *_empty;
|
||||||
|
|
||||||
static grow(len)
|
static grow(len)
|
||||||
unsigned len;
|
unsigned len;
|
||||||
{
|
{
|
||||||
register char *p;
|
register char *p;
|
||||||
register int click = CLICK_SIZE;
|
|
||||||
|
|
||||||
p = sbrk(0);
|
ASSERT(NextSlot(_top) == 0);
|
||||||
len += (char *) ALIGN((vir_bytes) p, sizeof(char *)) - p;
|
p = (char *) Align((ptrint)_top + len, BRKSIZE);
|
||||||
while (click >= 4) {
|
if (p < _top || brk(p) != 0)
|
||||||
unsigned len1 = ALIGN((vir_bytes) p + len + sizeof(char *), click) - (vir_bytes) p;
|
return(0);
|
||||||
char *p1 = p;
|
NextSlot(_top) = p;
|
||||||
if (p + len1 + BUGFIX < p || (p1 = sbrk(len1)) == (char *) -1) {
|
NextSlot(p) = 0;
|
||||||
click >>= 1;
|
free(_top);
|
||||||
continue;
|
_top = p;
|
||||||
}
|
return(1);
|
||||||
p = p1;
|
|
||||||
if (top + sizeof(char *) != p) {
|
|
||||||
/* someone else has done an sbrk */
|
|
||||||
NEXT(top) = (char *) ((vir_bytes) p | BUSY);
|
|
||||||
} else {
|
|
||||||
for (p = bottom; NEXT(p) != 0; p = (char *) (* (vir_bytes *) p & ~BUSY))
|
|
||||||
;
|
|
||||||
}
|
|
||||||
top = p + len1 - sizeof(char *);
|
|
||||||
NEXT(p) = top;
|
|
||||||
NEXT(top) = 0;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char *malloc(size)
|
char *malloc(size)
|
||||||
unsigned size;
|
unsigned size;
|
||||||
{
|
{
|
||||||
register char *p, *next, *new;
|
register char *prev, *p, *next, *new;
|
||||||
register unsigned len = ALIGN(size, sizeof(char *)) + sizeof(char *);
|
register unsigned len, ntries;
|
||||||
|
|
||||||
if ((p = bottom) == 0) {
|
if (size == 0)
|
||||||
p = sbrk(sizeof(char *));
|
size = PTRSIZE; /* avoid slots less that 2*PTRSIZE */
|
||||||
sbrk((char *) ALIGN((vir_bytes) p, sizeof(char *)) - p);
|
for (ntries = 0; ntries < 2; ntries++) {
|
||||||
p = (char *) ALIGN((vir_bytes) p, sizeof(char *));
|
len = Align(size, PTRSIZE) + PTRSIZE;
|
||||||
top = bottom = p;
|
if (_bottom == 0) {
|
||||||
NEXT(p) = 0;
|
p = sbrk(2 * PTRSIZE);
|
||||||
|
p = (char *) Align((ptrint)p, PTRSIZE);
|
||||||
|
p += PTRSIZE;
|
||||||
|
_top = _bottom = p;
|
||||||
|
NextSlot(p) = 0;
|
||||||
}
|
}
|
||||||
while ((next = NEXT(p)) != 0)
|
#ifdef SLOWDEBUG
|
||||||
if ((vir_bytes) next & BUSY) /* already in use */
|
for (p = _bottom; (next = NextSlot(p)) != 0; p = next)
|
||||||
p = (char *) ((vir_bytes) next & ~BUSY);
|
ASSERT(next > p);
|
||||||
else {
|
ASSERT(p == _top);
|
||||||
while ((new = NEXT(next)) != 0 && !((vir_bytes) new & BUSY))
|
#endif
|
||||||
next = new;
|
for (prev = 0, p = _empty; p != 0; prev = p, p = NextFree(p)) {
|
||||||
if (next - p >= len) { /* fits */
|
next = NextSlot(p);
|
||||||
if ((new = p + len) < next) /* too big */
|
new = p + len;
|
||||||
NEXT(new) = next;
|
if (new > next)
|
||||||
NEXT(p) = (char *) ((vir_bytes) new | BUSY);
|
continue; /* too small */
|
||||||
return(p + sizeof(char *));
|
if (new + PTRSIZE < next) { /* too big, so split */
|
||||||
|
/* + PTRSIZE avoids tiny slots on free list */
|
||||||
|
NextSlot(new) = next;
|
||||||
|
NextSlot(p) = new;
|
||||||
|
NextFree(new) = NextFree(p);
|
||||||
|
NextFree(p) = new;
|
||||||
}
|
}
|
||||||
p = next;
|
if (prev)
|
||||||
|
NextFree(prev) = NextFree(p);
|
||||||
|
else
|
||||||
|
_empty = NextFree(p);
|
||||||
|
return(p);
|
||||||
}
|
}
|
||||||
return grow(len) ? malloc(size) : 0;
|
if (grow(len) == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ASSERT(ntries != 2);
|
||||||
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *realloc(old, size)
|
char *realloc(old, size)
|
||||||
char *old;
|
char *old;
|
||||||
unsigned size;
|
unsigned size;
|
||||||
{
|
{
|
||||||
register char *p = old - sizeof(char *), *next, *new;
|
register char *prev, *p, *next, *new;
|
||||||
register unsigned len = ALIGN(size, sizeof(char *)) + sizeof(char *), n;
|
register unsigned len, n;
|
||||||
|
|
||||||
next = (char *) (* (vir_bytes *) p & ~BUSY);
|
len = Align(size, PTRSIZE) + PTRSIZE;
|
||||||
n = next - old; /* old size */
|
next = NextSlot(old);
|
||||||
while ((new = NEXT(next)) != 0 && !((vir_bytes) new & BUSY))
|
n = (int)(next - old); /* old length */
|
||||||
next = new;
|
/*
|
||||||
if (next - p >= len) { /* does it still fit */
|
* extend old if there is any free space just behind it
|
||||||
if ((new = p + len) < next) { /* even too big */
|
*/
|
||||||
NEXT(new) = next;
|
for (prev = 0, p = _empty; p != 0; prev = p, p = NextFree(p)) {
|
||||||
NEXT(p) = (char *) ((vir_bytes) new | BUSY);
|
if (p > next)
|
||||||
}
|
break;
|
||||||
|
if (p == next) { /* 'next' is a free slot: merge */
|
||||||
|
NextSlot(old) = NextSlot(p);
|
||||||
|
if (prev)
|
||||||
|
NextFree(prev) = NextFree(p);
|
||||||
else
|
else
|
||||||
NEXT(p) = (char *) ((vir_bytes) next | BUSY);
|
_empty = NextFree(p);
|
||||||
|
next = NextSlot(old);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
new = old + len;
|
||||||
|
/*
|
||||||
|
* Can we use the old, possibly extended slot?
|
||||||
|
*/
|
||||||
|
if (new <= next) { /* it does fit */
|
||||||
|
if (new + PTRSIZE < next) { /* too big, so split */
|
||||||
|
/* + PTRSIZE avoids tiny slots on free list */
|
||||||
|
NextSlot(new) = next;
|
||||||
|
NextSlot(old) = new;
|
||||||
|
free(new);
|
||||||
|
}
|
||||||
return(old);
|
return(old);
|
||||||
}
|
}
|
||||||
if ((new = malloc(size)) == 0) /* it didn't fit */
|
if ((new = malloc(size)) == 0) /* it didn't fit */
|
||||||
return(0);
|
return(0);
|
||||||
bcopy(old, new, n); /* n < size */
|
bcopy(old, new, n); /* n < size */
|
||||||
* (vir_bytes *) p &= ~BUSY;
|
free(old);
|
||||||
return(new);
|
return(new);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(p)
|
free(p)
|
||||||
char *p;
|
char *p;
|
||||||
{
|
{
|
||||||
* (vir_bytes *) (p - sizeof(char *)) &= ~BUSY;
|
register char *prev, *next;
|
||||||
|
|
||||||
|
ASSERT(NextSlot(p) > p);
|
||||||
|
for (prev = 0, next = _empty; next != 0; prev = next, next = NextFree(next))
|
||||||
|
if (p < next)
|
||||||
|
break;
|
||||||
|
NextFree(p) = next;
|
||||||
|
if (prev)
|
||||||
|
NextFree(prev) = p;
|
||||||
|
else
|
||||||
|
_empty = p;
|
||||||
|
if (next) {
|
||||||
|
ASSERT(NextSlot(p) <= next);
|
||||||
|
if (NextSlot(p) == next) { /* merge p and next */
|
||||||
|
NextSlot(p) = NextSlot(next);
|
||||||
|
NextFree(p) = NextFree(next);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (prev) {
|
||||||
|
ASSERT(NextSlot(prev) <= p);
|
||||||
|
if (NextSlot(prev) == p) { /* merge prev and p */
|
||||||
|
NextSlot(prev) = NextSlot(p);
|
||||||
|
NextFree(prev) = NextFree(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
static assert_failed()
|
||||||
|
{
|
||||||
|
write(2, "assert failed in lib/malloc.c\n", 30);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue