|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T m
Length: 15113 (0x3b09)
Types: TextFile
Names: »malloc.c«
└─⟦2d1937cfd⟧ Bits:30007241 EUUGD22: P.P 5.0
└─⟦35176feda⟧ »EurOpenD22/isode/isode-6.tar.Z«
└─⟦de7628f85⟧
└─⟦this⟧ »isode-6.0/quipu/malloc.c«
/* malloc.c - Quipu DSA specific memory management */
#ifndef lint
static char *rcsid = "$Header: /f/osi/quipu/RCS/malloc.c,v 7.0 89/11/23 22:20:55 mrose Rel $";
#endif
/*
* $Header: /f/osi/quipu/RCS/malloc.c,v 7.0 89/11/23 22:20:55 mrose Rel $
*
*
* $Log: malloc.c,v $
* Revision 7.0 89/11/23 22:20:55 mrose
* Release 6.0
*
*/
/*
* NOTICE
*
* Acquisition, use, and distribution of this module and related
* materials are subject to the restrictions of a license agreement.
* Consult the Preface in the User's Manual for the full terms of
* this agreement.
*
*/
#include <stdio.h>
#include "quipu/malloc.h"
#include "quipu/util.h"
#include "manifest.h"
#include <sys/types.h>
static int malloc_file = 0;
#ifdef QUIPU_MALLOC
extern LLog * log_dsap;
extern SFD attempt_restart();
#if defined(DEBUG) && defined(sun3)
#define MALLOCSTACK
#endif
#ifdef MALLOCSTACK
#include <sys/file.h>
off_t lseek();
#ifndef MALLOCTRACE
#define MALLOCTRACE
#endif
#else
#define write_stack(x)
#endif
#define MAXHEAP 100 /* Number of heaps */
#ifndef BSD42
#define PAGESIZE 0x2000 /* The systems memory page size */
#else
#define PAGESIZE pagesize
#endif
#define ALIGN(x) (((x) + (sizeof(char *) - 1)) & ~(sizeof(char *) - 1))
#define PAGEALIGN(x) (((x) + (PAGESIZE-1)) & ~(PAGESIZE-1))
#define SMALLMAX 65536 /* largest block a short can reference */
struct header {
union {
struct {
unsigned short control;
unsigned short size;
} small;
unsigned int big;
} un;
};
#define bigsize un.big
#define smallsize un.small.size
#define use un.small.control
#define INUSE 0x1000
#define USED(x) (x->use & INUSE)
/* sizes chosen for anticipated QUIPU behaviour */
#define BUCKETS 11
static unsigned sizes [BUCKETS] = { 0, 12, 16, 24, 48, 64, 128, 256, 512, 8191, 0 };
struct freelist {
struct header * block;
unsigned int size;
struct freelist * next;
struct freelist * prev;
};
struct freehead {
struct header head;
struct freelist * flist;
};
static struct freelist heaps[MAXHEAP][BUCKETS];
static struct freelist *heapptr[MAXHEAP];
static struct freelist bigmem = { 0,0,&bigmem, &bigmem};
static struct freelist *bigfree = &bigmem;
static struct freelist freemem = { 0,0,&freemem, &freemem};
static struct freelist *listfree = &freemem;
static int first_malloc = 1;
static char * top_mem;
#ifdef BSD42
static int pagesize = 0x2000;
#endif
extern caddr_t sbrk();
#ifdef MALLOCTRACE
static int malloc_started = 0;
static char * malloc_fname = (char *)0;
#endif
#ifndef MALLOCTRACE
/* ARGSUSED */
#endif
#endif
start_malloc_trace(f)
char * f;
{
#ifdef MALLOCTRACE
char * env, *getenv ();
if (((env = getenv ("TRACE_MEMORY")) == (char *)0) || (*env == 0))
return;
if (! malloc_started) {
if (f == (char *)0)
malloc_fname = "memory.out";
else
malloc_fname = f;
malloc_file = creat (malloc_fname,0644);
malloc_started = 1;
} else {
malloc_file = open (malloc_fname,1);
(void) lseek (malloc_file,0l,2);
}
#else
malloc_file = 0;
#endif
}
stop_malloc_trace ()
{
#ifdef MALLOCTRACE
if (malloc_file)
(void) close (malloc_file);
#endif
malloc_file = 0;
}
#ifdef QUIPU_MALLOC
#ifdef MALLOCTRACE
static write_string (p)
char *p;
{
register char *q;
if (!malloc_file)
return;
q = p;
while (*q++)
;
(void) write(malloc_file, p, q-p-1);
}
static write_addr(addr)
char *addr;
{
char buf[20];
static char hex[] = "0123456789abcdef";
char *ptr;
int x;
if (!malloc_file)
return;
x = (int) addr;
if (x == 0) {
(void) write(malloc_file, "0 ",2);
return;
}
ptr = buf;
while (x > 0)
*ptr++ = hex[x % 16], x /= 16;
*ptr = 0;
while (ptr != buf)
(void) write(malloc_file, --ptr,1);
(void) write (malloc_file," ",1);
}
static write_int(x)
unsigned x;
{
char buf[20];
static char dec[] = "0123456789";
char *ptr;
if (!malloc_file)
return;
if (x == 0) {
(void) write(malloc_file, "0 ",2);
return;
}
ptr = buf;
while (x > 0)
*ptr++ = dec[x % 10], x /= 10;
while (ptr != buf)
(void) write(malloc_file, --ptr,1);
(void) write (malloc_file," ",1);
}
static char * log_realloc (oldlen,newlen,bsize,addr)
unsigned oldlen,newlen,bsize;
char * addr;
{
write_string ("realloc of "); write_int (oldlen);
write_string ("at "); write_addr (addr);
write_string ("\n");
write_stack("x");
write_string ("realloc-to of "); write_int (newlen);
write_string ("gets "); write_int (bsize);
write_string ("at "); write_addr (addr);
write_string ("\n");
write_stack("x");
}
static print_free_list (heap)
unsigned heap;
{
int i;
struct freelist * top;
struct freelist * ptr;
write_string ("free list for heap ");write_int(heap);write_string(":\n");
for (i=0; i<BUCKETS; i++) {
top = &heaps[heap][i];
write_int (sizes[i]); write_string (": ");
for (ptr = top->next ; ptr != top; ptr=ptr->next)
write_int (ptr->size);
write_string ("\n");
}
}
#ifdef MALLOCSTACK
/* ever so slightly machine dependant !!! */
static write_stack (x)
char * x;
{
struct stackframe {
struct stackframe *next;
char *addr;
} * frame;
for (frame = ((struct stackframe *)(&x-2))->next ; frame; frame = frame->next) {
write_string ("C ");
write_addr ((char *)frame->addr);
write_string ("\n");
}
write_string ("\n");
}
#endif
#endif
static return_freelist (next)
struct freelist *next;
{
next->next = listfree->next;
next->prev = listfree;
listfree->next->prev = next;
listfree->next = next;
}
static struct freelist * new_freelist ()
{
struct freelist * flist;
flist = listfree->next;
if (flist == listfree) {
int i;
struct freelist * next;
/* go and get some more */
if ((flist = (struct freelist *) sbrk (PAGESIZE)) == (struct freelist *)0) {
/* there are 100s of places where Quipu would choke on a naff malloc */
attempt_restart (-2);
return ((struct freelist *)0);
}
top_mem = (char *)flist + PAGESIZE;
next = (struct freelist *)flist;
next++;
for (i=sizeof (struct freelist); i< PAGESIZE ; i+=sizeof (struct freelist))
return_freelist (next++);
} else {
flist->prev->next = flist->next;
flist->next->prev = flist->prev;
}
return (flist);
}
static char * big_malloc (realsize)
/* used for mallocs of > MAXSMALL */
unsigned realsize;
{
unsigned blocksize;
struct freelist * flist;
struct header * head = (struct header *)0;
char * mem;
for (flist = bigfree->next; flist != bigfree; flist=flist->next) {
if (flist->size >= realsize) {
head = flist->block;
flist->prev->next = flist->next;
flist->next->prev = flist->prev;
return_freelist (flist);
break;
}
}
if (head == (struct header *)0) {
/* go and get on then !!! */
blocksize = PAGEALIGN(realsize);
if ((head = (struct header *) sbrk ((int)blocksize)) == (struct header *)0) {
/* there are 100s of places where Quipu would choke on a naff malloc */
attempt_restart (-2);
return ((char *)0);
}
top_mem = (char *)head + blocksize;
head->bigsize = blocksize | 0x01;
} else
head->bigsize |= 0x01;
mem = (char *) head + ALIGN(sizeof (struct header));
#ifdef MALLOCTRACE
write_string ("gets "); write_int (head->bigsize);
write_string ("at "); write_addr (mem);
write_string ("\n");
write_stack("x");
#endif
return (mem);
}
static big_free (ptr)
struct header *ptr;
{
struct freelist *next;
struct freehead *x;
if ((next = new_freelist ()) == (struct freelist *)0)
return;
next->size=ptr->bigsize;
next->block = ptr;
ptr->bigsize &= ~1;
next->next = bigfree->next;
next->prev = bigfree;
bigfree->next->prev = next;
bigfree->next = next;
x = (struct freehead *) ptr;
x->flist = next;
}
static which_list (size)
register unsigned size;
{
register unsigned * p;
p = sizes;
p [BUCKETS -1] = size; /* force stop to while loop */
while ( size > *p++ )
;
return ( (p-1) - sizes);
}
static add_free (x)
struct header * x;
{
struct freelist *next, *c;
struct freehead *ptr;
x->use &= ~INUSE;
if ((c = heapptr[x->use]) == (struct freelist *) 0)
c = heapptr[x->use] = heaps[x->use];
c = &c[which_list(x->smallsize)];
if ((next = new_freelist ()) == (struct freelist *)0)
return;
next->size=x->smallsize;
next->block = x;
next->next = c->next;
next->prev = c;
c->next->prev = next;
c->next = next;
ptr = (struct freehead *) x;
ptr->flist = next;
}
static remove_free (a)
register struct freelist * a;
{
a->block->use |= INUSE;
a->prev->next = a->next;
a->next->prev = a->prev;
return_freelist(a);
}
static struct header * next_free_block (ptr)
register struct header * ptr;
{
register struct header * next;
next = (struct header *)((char *)ptr + ptr->smallsize);
if (PAGEALIGN((int)ptr) != PAGEALIGN((int)next + 1))
return (struct header *)0;
if (((char *)next < top_mem) && (next->use == (ptr->use & ~INUSE)))
return (next);
return (struct header *)0;
}
static struct header * find_block (size)
unsigned size;
{
register struct freelist * top;
register struct freelist * ptr;
register int i;
#ifdef BESTFIT
struct freelist * best = (struct freelist *)0;
#endif
if ((top = heapptr[mem_heap]) == (struct freelist *)0)
return ((struct header *) 0);
top = &top[i = which_list (size)];
for (; i < BUCKETS ; i++,top++ ) {
for (ptr = top->next ; ptr != top; ptr=ptr->next) {
if (ptr->size >= size) {
#ifdef BESTFIT
if (ptr->size == size) {
remove_free (ptr);
return (&(ptr->block));
}
if ( (best == (struct freelist *)0)
|| (ptr->size < best->size))
best = ptr;
#else
remove_free (ptr);
return (ptr->block);
#endif
}
}
#ifdef BESTFIT
if (best != (struct freelist *)0) {
remove_free (best);
return (&(best->block));
}
#endif
}
return (struct header *)0;
}
static use_block (ptr,size)
register struct header *ptr;
register unsigned size;
{
register struct header *next;
if ((ptr->smallsize == size) || (ptr->smallsize < size + sizeof (struct freehead)))
return; /* don't split it -> left with block too small for use */
next = (struct header *)((char *)ptr + size);
next->smallsize = ptr->smallsize - size;
next->use = ptr->use & ~INUSE;
ptr->smallsize = size;
ptr->use |= INUSE;
add_free (next);
}
char * malloc (size)
register unsigned size;
{
char * mem;
struct header *head;
register unsigned realsize, blocksize;
#ifdef BSD42
if (first_malloc)
pagesize = getpagesize ();
#endif
if (mem_heap >= MAXHEAP)
mem_heap = MAXHEAP - 1;
if (size < sizeof (struct freelist *)) /* memory will be used when freed for freelist !!! */
realsize = ALIGN (sizeof (struct freehead));
else
realsize = ALIGN (size) + ALIGN (sizeof (struct header));
if (realsize >= SMALLMAX) {
#ifdef MALLOCTRACE
write_string ("malloc of "); write_int (size);
#endif
return (big_malloc (realsize));
}
if (first_malloc) {
/* set up freelist */
unsigned x;
int i,j;
for (i = 0; i < MAXHEAP; i++) {
heapptr[i] = (struct freelist *) 0;
for (j = 0 ; j<BUCKETS; j++) {
heaps[i][j].prev = &heaps[i][j];
heaps[i][j].next = &heaps[i][j];
heaps[i][j].size = 0;
}
}
/* align first sbrk to page boundary */
x = (unsigned)sbrk(0);
x = PAGEALIGN (x) - x;
blocksize = PAGEALIGN(realsize) + x;
if ((head = (struct header *) sbrk ((int)blocksize)) == (struct header *)0) {
/* there are 100s of places where Quipu would choke on a naff malloc */
attempt_restart (-2);
return ((char *)0);
}
head->smallsize = blocksize;
top_mem = (char *)head + blocksize;
first_malloc = 0;
head->use = INUSE | mem_heap;
use_block (head,realsize);
} else if ((head = find_block (realsize)) == (struct header *)0) {
blocksize = PAGEALIGN(realsize);
if ((head = (struct header *) sbrk ((int)blocksize)) == (struct header *)0) {
/* there are 100s of places where Quipu would choke on a naff malloc */
attempt_restart (-2);
return ((char *)0);
}
head->smallsize = blocksize;
top_mem = (char *)head + blocksize;
head->use = INUSE | mem_heap;
use_block (head,realsize);
} else
use_block (head,realsize);
mem = (char *) head + ALIGN(sizeof (struct header));
#ifdef MALLOCTRACE
write_string ("malloc of "); write_int (size);
write_string ("gets "); write_int (head->smallsize);
write_string ("at "); write_addr (mem);
write_string ("heap ");write_int (mem_heap);
write_string ("\n");
write_stack("x");
#endif
return (mem);
}
free(s)
char *s;
{
struct header * ptr;
struct header * next;
ptr = (struct header *) (s - ALIGN (sizeof (struct header)));
if (ptr->smallsize & 1) {
#ifdef MALLOCTRACE
write_string ("free of "); write_int (ptr->bigsize);
write_string ("at "); write_addr (s);
write_string ("heap (big)\n");
write_stack("x");
#endif
big_free (ptr);
return;
}
#ifdef MALLOCTRACE
write_string ("free of "); write_int (ptr->smallsize);
write_string ("at "); write_addr (s);
write_string ("heap "); write_int (ptr->use & ~INUSE);
write_string ("\n");
write_stack("x");
#endif
if (! USED(ptr)) {
LLOG (log_dsap,LLOG_EXCEPTIONS,("freeing problem"));
return; /* already freed !!! */
}
/* join forward free block in loop to catch previous back blocks ! */
while ((next = next_free_block(ptr)) != (struct header *) 0) {
ptr->smallsize += next->smallsize;
remove_free (((struct freehead *)next)->flist);
}
add_free (ptr);
return;
}
char *realloc(s, n)
char *s;
register unsigned n;
{
char * mem;
register unsigned realsize;
struct header * ptr;
struct header * next;
ptr = (struct header *) (s - ALIGN (sizeof (struct header)));
if (ptr->smallsize & 1) {
DLOG (log_dsap,LLOG_DEBUG,("re-alloc of big block"));
#ifdef MALLOCTRACE
write_stack ("x");
#endif
goto out;
}
if (! USED(ptr)) {
LLOG (log_dsap,LLOG_EXCEPTIONS,("re-alloc problem"));
#ifdef MALLOCTRACE
write_stack ("x");
#endif
goto out;
}
realsize = ALIGN (n) + ALIGN (sizeof (struct header));
if (ptr->smallsize >= realsize) {
#ifdef MALLOCTRACE
log_realloc (ptr->smallsize,realsize,ptr->smallsize,s);
#endif
return (s);
}
/* see if next block is free */
if ((next = next_free_block(ptr)) != (struct header *) 0) {
struct header * top;
top = next;
/* join with other free blocks */
while ((next = next_free_block(top)) != (struct header *) 0) {
top->smallsize += next->smallsize;
remove_free (((struct freehead *)next)->flist);
}
remove_free (((struct freehead *)top)->flist);
/* is it big enough ? */
if (ptr->smallsize + top->smallsize >= realsize) {
#ifdef MALLOCTRACE
unsigned savesize;
savesize = ptr->smallsize;
#endif
ptr->smallsize += top->smallsize;
use_block (ptr,realsize);
#ifdef MALLOCTRACE
log_realloc (savesize,realsize,ptr->smallsize,s);
#endif
return (s);
} else
/* return to free list */
add_free (top);
}
out:;
if ((mem = malloc (n)) == (char *)0)
return ((char *)0);
bcopy (s,mem,(int)n);
free (s);
return (mem);
}
char *calloc(n, size)
unsigned n, size;
{
char * mem;
unsigned x;
x= n*size;
if ((mem = malloc (x)) == (char *)0)
return ((char *)0);
bzero (mem,(int)x);
return (mem);
}
void
cfree(mem)
char * mem;
{
free(mem);
}
#endif