home *** CD-ROM | disk | FTP | other *** search
-
- /*
- 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();
- }
- }
- */
-