home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume5
/
malloc.uport
/
malloc.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-02-03
|
13KB
|
514 lines
/*
Fast Malloc for Microport 286
Copyright (C) April 1988
Michael Grenier
Permission to redistribute for non-profit use is hereby granted.
Please send bug fixes to mike@cimcor.mn.org
*/
#include <stdio.h>
#include <memory.h>
/* TUNABLE PARAMETERS */
#define EPSILON 10 /* Blocks smaller than this number of words are not
retained */
/* DO NOT CHANGE! */
#define ALLOCATED 1
#define AVAILABLE 0
#define MAX_BLOCK_SIZE 32744 /* maximum size block we can allocate -
32768 - 4 * HEADER_SIZE words */
#define LLINK(x) (page[x]) /* pointer to previous block in page */
#define TAG(x) (page[x+1]) /* set to 1 if allocated */
#define SIZE(x) (page[x+2]) /* Number of words in this block not counting header */
#define RLINK(x) (page[x+3]) /* pointer to next block */
#define ETAG(x) (page[x+SIZE(x)+4]) /* set to 1 if allocated */
#define ULINK(x) (page[x+SIZE(x)+5]) /* pointer to beginning of this block */
#define AV(indx) (av_list[indx]) /* pointer to block on free list with this page */
static char *xxcopyright="\n\n\nCopyright 1988 by Michael Grenier, all rights reserved\n\n";
char *sbrk(); /* needed Unix System calls */
int brk();
static unsigned av_list[62], /* offset pointer to a free block with each page */
m_curindx=0, /* Current page to allocate from */
free_indx=1; /* Page to begin searching for a block in */
static int xxfunny[4]={23,56,12,23}; /* used to uniquely identify this binary should
someone steal the start distributing binaries
and delete the copyright */
#define HEADER_SIZE 6 /* words wasted per block */
#define ALLOCATE_OFFSET 4 /* Offset in block where user process pointer points */
static long m_endds, m_first_endds; /* address of current and initial brk() value */
/* Get starting address of this segment given segment number
starting with one as the first segment allocated
*/
unsigned int *getpage(indx)
unsigned indx;
{
return (unsigned int *) ((m_first_endds + ((unsigned long)indx - 1L)
* 0x00080000L) & 0xFFFF0000L); /* adjust selector */
}
/* can't use stock memcpy, memset as they don't handle a size
greater than 32K bytes */
void u_memset(ptr, value, size) /* in words */
unsigned int *ptr, value, size;
{
while (!size)
{
(*(ptr++)) = value;
size--;
}
}
void u_memcpy(ptr1, ptr2, size) /* in words, should be written in asssembler ti use block moves */
unsigned int *ptr1, *ptr2, size;
{
while (!size)
{
(*(ptr1++)) = *(ptr2++);
size--;
}
}
/*
New_page() - allocate a new segment from Unix
This routine allocates a full 64K segment to be supplied to malloc
to be split up as appropiate
*/
void new_page()
{
unsigned temp, *page;
if (m_curindx==0) /* First time so initialize a segment */
{
m_first_endds = (long) sbrk(0); /* returns next segment value */
m_endds = m_first_endds + 65535L;
}
else
m_endds += 0x00080000L; /* add one to 80286 selector */
brk((char *) m_endds); /* allocates the new page (segment) */
/* Now set up free list in segment. Allocate and tag busy two zero
length blocks on each end of page to simplify and speed up
allocation algorithm - see Sahni's notes. Also allocate a
zero length free segment and set AV to point to it.
*/
m_curindx++; /* Update number of pages allocated */
page = getpage (m_curindx); /* set up to use macros */
TAG(0) = ALLOCATED; /* allocate zero length block at start of page */
SIZE(0) = 0;
ETAG(0) = ALLOCATED;
ULINK(0)= 0;
temp = 32768 - HEADER_SIZE;/* point to last possible block in page
and allocate it also */
TAG(temp) = ALLOCATED;
SIZE(temp) = 0;
ETAG(temp) = ALLOCATED;
ULINK(temp) = temp;
temp = HEADER_SIZE; /* Now allocate a zero length free block that
will never get allocated (because of its size) */
TAG(temp) = AVAILABLE;
SIZE(temp) = 0;
LLINK(temp) = temp + HEADER_SIZE; /* point to next block (yet to be
created) which will be the actual
free block */
ETAG(temp) = AVAILABLE;
ULINK(temp) = temp;
RLINK(temp) = temp + HEADER_SIZE;
av_list[m_curindx] = temp; /* point to first free block */
temp += HEADER_SIZE; /* Finally, allocate the actual free block */
TAG(temp) = AVAILABLE; /* mark as free */
SIZE(temp) = MAX_BLOCK_SIZE;
LLINK(temp) = HEADER_SIZE; /* point to previous free block */
RLINK(temp) = HEADER_SIZE;
ETAG(temp) = AVAILABLE;
ULINK(temp) = temp;
}
unsigned int get_offset(ptr)
unsigned int *ptr; /* not char * because we want pointer math in words, not bytes */
{
unsigned int temp = (((unsigned) ptr >>1) - ALLOCATE_OFFSET);
return temp;
}
void free_from_page(p, seqindx)
unsigned int p, seqindx;
{
unsigned int n, q, r, *page;
/* point to true beginning of block */
page = getpage(seqindx);
if ((TAG(p) != ALLOCATED) || (ETAG(p) != ALLOCATED))
{
fprintf(stderr,"\n\rAttempt to free a pointer which was not allocated\n");
fprintf(stderr,"or had its control block information overwritten!\n");
abort();
}
n = SIZE(p);
if (((p==12) || (page[p-2]==ALLOCATED))
&& (TAG(p+n+HEADER_SIZE)==ALLOCATED))
/* free this block but do not join with neighbors */
{
TAG(p) = AVAILABLE;
ETAG(p) = AVAILABLE;
ULINK(p) = p;
LLINK(p) = AV(seqindx);
RLINK(p) = RLINK(AV(seqindx));
/* LLINK(RLINK(p) = p; Can't seem to nest macros */
page [ RLINK(p) ] = p;
RLINK(AV(seqindx)) = p;
}
else if ((p!=12) && /* Never join with first empty block as AV must point to something */
(page[p-2]==AVAILABLE) &&
((TAG(p+n+HEADER_SIZE))==ALLOCATED))
/* join with left block */
{
q = page[p-1]; /* start of left block */
SIZE(q) = SIZE(q) + n + HEADER_SIZE;
ULINK(p) = q;
ETAG(p) = AVAILABLE;
AV(seqindx) = q; /* always leave AV pointing to possible full block */
}
else if (((p==12) || (page[p-2]==ALLOCATED)) &&
((TAG(p+n+HEADER_SIZE))==AVAILABLE))
/* join with right block */
{
q = p + n + HEADER_SIZE; /* start of next block */
page[ page[q] + 3] = p; /* RLINK(LLINK(q))=p stupid macros...*/
page[page[q+3]]=p; /*LLINK(RLINK(q)) = p; */
LLINK(p) = LLINK(q);
RLINK(p) = RLINK(q);
SIZE(p) = n + HEADER_SIZE + SIZE(q);
ULINK(p) = p;
TAG(p) = AVAILABLE;
AV(seqindx)=p; /* Can't have free list pointer pointing to
garbage! */
}
else
{
/* join with both sides */
q = p + n + HEADER_SIZE; /* start of next block */
r = page[p - 1]; /* start of previous block */
RLINK(LLINK(q))=RLINK(q);
LLINK(RLINK(q))=LLINK(q);
SIZE(r)=SIZE(r) + (n + HEADER_SIZE) + SIZE(q) + HEADER_SIZE;
ULINK(r)=r;
AV(seqindx)=r; /* don't point to garbage */
}
}
unsigned int *allocate_from_page(n, seqindx)
unsigned int n, seqindx;
{
unsigned int p, diff, *page;
page = getpage(seqindx);
p = AV(seqindx); /* point to first free block */
do
{ /* search for a free block, first fit */
if (SIZE(p) >= n) /* allocate it */
{
diff=SIZE(p)-n;
if (diff < EPSILON) /* allocate whole block */
{
RLINK(LLINK(p)) = RLINK(p);
LLINK(RLINK(p)) = LLINK(p);
TAG(p) = ALLOCATED;
ETAG(p) = ALLOCATED;
AV(seqindx) = LLINK(p);
return(page + p + ALLOCATE_OFFSET);
}
else
{ /* free lower portion of block */
SIZE(p) = diff - HEADER_SIZE; /* remaining free portion */
ULINK(p) = p;
ETAG(p) = AVAILABLE;
AV(seqindx) = p;
/* allocate the rest of block */
p += SIZE(p) + HEADER_SIZE; /* point to start of block */
SIZE(p) = n;
TAG(p) = ALLOCATED;
ETAG(p) = ALLOCATED;
ULINK(p) = p;
return (page + p + ALLOCATE_OFFSET);
}
}
p = RLINK(p); /* point to next free block */
} while (p != AV(seqindx));
return ((unsigned int *) 0);
}
void return_free_pages()
{
unsigned i, *page; /* leave one page allocated because this
#*#*!& UNIX won't give you the intial brk value */
while ((m_curindx>1) && (page=getpage(m_curindx),
SIZE(AV(m_curindx)) == MAX_BLOCK_SIZE))
{
m_curindx--;
m_endds -= 0x00080000L; /* subtract one from selector */
};
brk( (char *) m_endds);
}
char *malloc(size)
unsigned size;
{
char *dummy;
int indx;
if (m_curindx==0)
if (!new_page()) return((char *) 0); /* no more memory */
/* calculate page address */
indx=free_indx;
do
{
if ((dummy = (char *) allocate_from_page((size+1)>>1, indx))
!=NULL)
{
free_indx=indx; /* to speed up allocating for next malloc */
return ((char *) dummy);
}
indx++;
if (indx>m_curindx) indx=1;
} while (indx != free_indx);
/* -- if we haven't returned yet, call brk for more memory and try again */
if (!new_page()) return((char *) 0);
return((char *) allocate_from_page((size+1)>>1, m_curindx));
}
char *calloc(nelem, elsize)
unsigned nelem, elsize;
{
char *dum;
register unsigned size;
size = nelem*elsize; /* in bytes, assume compiler word aligns structures */
if ((dum=malloc(size)) != NULL) /* zero out the block */
u_memset( (int *) dum, 0, size>>1); /* set size words to 0 */
return dum;
}
void free(ptr)
char *ptr;
{
unsigned int indx;
long temp;
temp = (long) ptr - m_first_endds;
indx = (temp >>19) + 1; /* get selector for pointer */
free_from_page(get_offset((unsigned int *)ptr), indx);
return_free_pages();
}
char *realloc( ptr, size)
char *ptr;
unsigned size;
{
unsigned int seqindx, *page, rb, p, diff;
long temp;
char * ptrnew;
if (size==0)
{
free(ptr);
return (char *) NULL;
}
temp = (long) ptr - m_first_endds;
seqindx = (temp >>19) + 1; /* get selector for pointer */
page = getpage(seqindx);
p = get_offset((unsigned int *) ptr);
size = (size + 1) >>1; /* bytes to words, round up */
diff = SIZE(p) - size; /* in words */
if (size <= SIZE(p)) /* words, reduce space */
{
unsigned int rbnew;
if (diff<HEADER_SIZE)
return ptr; /* if can't create a new free block then */
/* waste the few bytes */
SIZE(p) -= diff; /* modify this block */
ULINK(p) =p;
ETAG(p) = ALLOCATED;
rbnew = p + HEADER_SIZE + SIZE(p); /* build new right block */
TAG(rbnew) = ALLOCATED;
SIZE(rbnew) = diff - HEADER_SIZE;
ETAG(rbnew) = ALLOCATED;
ULINK(rbnew) = rbnew;
free_from_page(rbnew, seqindx);
return(ptr);
}
/* enlarging space */
rb=p+SIZE(p)+HEADER_SIZE; /* see if space is available from next block*/
diff= -diff;
if ((TAG(rb)==AVAILABLE) && ((SIZE(rb)+1)>diff))
{ /* take from right block - save important info */
unsigned int lsave, rsave, ssave;
lsave=LLINK(rb);
rsave=RLINK(rb);
ssave=SIZE(rb);
SIZE(p) = size;
ULINK(p) = p;
ETAG(p) = ALLOCATED;
rb = p + SIZE(p) + HEADER_SIZE;
/* fix right block */
LLINK(rb) = lsave;
RLINK(rb) = rsave;
TAG(rb) = AVAILABLE;
SIZE(rb) = ssave - diff;
ETAG(rb) = AVAILABLE; /* shouldn't have changed but ... */
ULINK(rb) = rb;
/* fix neighbors on free list */
LLINK(RLINK(rb)) = rb;
RLINK(LLINK(rb)) = rb;
return ptr;
}
/* Finally, if room wasn't availble, allocate new block and move stuff */
ptrnew = malloc(size<<1);
u_memcpy((int *) ptr, (int *) ptrnew, SIZE(p));
free (ptr);
return ptrnew;
}
char *tagit(i)
unsigned int i;
{
if (i==AVAILABLE)
return "AVAIL ";
if (i==ALLOCATED)
return "IN USE";
return "*BAD* ";
}
int dump_malloc()
{
unsigned int indx, ptr, *page;
if (m_curindx==0)
{
fprintf(stderr,"\r\n No segments allocated\r\n");
return(1);
}
for (indx=1; indx<=m_curindx; indx++)
{
fprintf(stderr,"\r\n Segment No. %d : \r\n",indx);
page=getpage(indx);
ptr = 0; /* first block */
fprintf(stderr," Ptr Block\r\n");
fprintf(stderr," Addr offset LLINK TAG SIZE RLINK ETAG UPLINK\r\n\n");
while (ptr!=32768 /* last block */ )
{
fprintf(stderr,"%.8lx %.5u %.5u %s %.5u %.5u %s %.5u \r\n",
page + ptr + ALLOCATE_OFFSET,
ptr, LLINK(ptr), tagit(TAG(ptr)), SIZE(ptr), RLINK(ptr),
tagit(ETAG(ptr)), ULINK(ptr));
ptr += HEADER_SIZE+SIZE(ptr);
if (ptr<6) abort();
}
fprintf(stderr," \r\n AV points to %u\r\n\n",AV(indx));
}
return(1);
}
/* int check_malloc()
{
char pointers[32762];
unsigned int first, cur, indx, *page;
for (indx=1; indx<=m_curindx; indx++);
{
fprintf("\nChecking segment %d for LLINKS\n", indx);
for (cur==0; cur<32762; cur++)
pointers[cur]=0;
page=getpage(indx);
first=AV(indx);
cur=first;
while (pointers[cur]==0)
{
pointers[cur]=1;
cur=LLINK(cur);
}
if (cur != first)abort();
fprintf("\nChecking segment %d for RLINKS\n", indx);
for (cur==0; cur<32760; cur++)
pointers[cur]=0;
page=getpage(indx);
first=AV(indx);
cur=first;
while (pointers[cur]==0)
{
pointers[cur]=1;
cur=RLINK(cur);
}
if (cur != first)abort();
}
}
*/