home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Carousel
/
CAROUSEL.cdr
/
mactosh
/
lang
/
xlisp.sha
/
xldmem.c
< prev
next >
Wrap
C/C++ Source or Header
|
1985-02-17
|
7KB
|
341 lines
/* xldmem - xlisp dynamic memory management routines */
#include "xlisp.h"
/* useful definitions */
#define ALLOCSIZE (sizeof(struct segment) + (anodes-1) * sizeof(NODE))
/* external variables */
extern NODE *oblist,*keylist;
extern NODE *xlstack;
extern NODE *xlenv,*xlnewenv;
extern long total;
extern int anodes,nnodes,nsegs,nfree,gccalls;
extern struct segment *segs;
extern NODE *fnodes;
/* external procedures */
extern char *malloc();
extern char *calloc();
/* newnode - allocate a new node */
NODE *newnode(type)
int type;
{
NODE *nnode;
/* get a free node */
if ((nnode = fnodes) == NIL) {
gc();
if ((nnode = fnodes) == NIL)
xlabort("insufficient node space");
}
/* unlink the node from the free list */
fnodes = cdr(nnode);
nfree -= 1;
/* initialize the new node */
nnode->n_type = type;
rplacd(nnode,NIL);
/* return the new node */
return (nnode);
}
/* stralloc - allocate memory for a string adding a byte for the terminator */
char *stralloc(size)
int size;
{
char *sptr;
/* allocate memory for the string copy */
if ((sptr = malloc(size+1)) == NULL) {
gc();
if ((sptr = malloc(size+1)) == NULL)
xlfail("insufficient string space");
}
total += (long) (size+1);
/* return the new string memory */
return (sptr);
}
/* strsave - generate a dynamic copy of a string */
char *strsave(str)
char *str;
{
char *sptr;
/* create a new string */
sptr = stralloc(strlen(str));
strcpy(sptr,str);
/* return the new string */
return (sptr);
}
/* strfree - free string memory */
strfree(str)
char *str;
{
total -= (long) (strlen(str)+1);
free(str);
}
/* gc - garbage collect */
gc()
{
NODE *p;
/* mark all accessible nodes */
mark(oblist); mark(keylist);
mark(xlenv);
mark(xlnewenv);
/* mark the evaluation stack */
for (p = xlstack; p; p = cdr(p))
mark(car(p));
/* sweep memory collecting all unmarked nodes */
sweep();
/* if there's still nothing available, allocate more memory */
if (fnodes == NIL)
addseg();
/* count the gc call */
gccalls++;
}
/* mark - mark all accessible nodes */
LOCAL mark(ptr)
NODE *ptr;
{
NODE *this,*prev,*tmp;
/* just return on nil */
if (ptr == NIL)
return;
/* initialize */
prev = NIL;
this = ptr;
/* mark this list */
while (TRUE) {
/* descend as far as we can */
while (TRUE) {
/* check for this node being marked */
if (this->n_flags & MARK)
break;
/* mark it and its descendants */
else {
/* mark the node */
this->n_flags |= MARK;
/* follow the left sublist if there is one */
if (livecar(this)) {
this->n_flags |= LEFT;
tmp = prev;
prev = this;
this = car(prev);
rplaca(prev,tmp);
}
/* otherwise, follow the right sublist if there is one */
else if (livecdr(this)) {
this->n_flags &= ~LEFT;
tmp = prev;
prev = this;
this = cdr(prev);
rplacd(prev,tmp);
}
else
break;
}
}
/* backup to a point where we can continue descending */
while (TRUE) {
/* check for termination condition */
if (prev == NIL)
return;
/* check for coming from the left side */
if (prev->n_flags & LEFT)
if (livecdr(prev)) {
prev->n_flags &= ~LEFT;
tmp = car(prev);
rplaca(prev,this);
this = cdr(prev);
rplacd(prev,tmp);
break;
}
else {
tmp = prev;
prev = car(tmp);
rplaca(tmp,this);
this = tmp;
}
/* otherwise, came from the right side */
else {
tmp = prev;
prev = cdr(tmp);
rplacd(tmp,this);
this = tmp;
}
}
}
}
/* sweep - sweep all unmarked nodes and add them to the free list */
LOCAL sweep()
{
struct segment *seg;
NODE *p;
int n;
/* empty the free list */
fnodes = NIL;
nfree = 0;
/* add all unmarked nodes */
for (seg = segs; seg != NULL; seg = seg->sg_next) {
p = &seg->sg_nodes[0];
for (n = seg->sg_size; n--; p++)
if (!(p->n_flags & MARK)) {
switch (ntype(p)) {
case STR:
if (p->n_strtype == DYNAMIC && p->n_str != NULL)
strfree(p->n_str);
break;
case FPTR:
if (p->n_fp)
fclose(p->n_fp);
break;
}
p->n_type = FREE;
p->n_flags = 0;
rplaca(p,NIL);
rplacd(p,fnodes);
fnodes = p;
nfree++;
}
else
p->n_flags &= ~(MARK | LEFT);
}
}
/* addseg - add a segment to the available memory */
int addseg()
{
struct segment *newseg;
NODE *p;
int n;
/* check for zero allocation */
if (anodes == 0)
return (FALSE);
/* allocate a new segment */
if ((newseg = (struct segment *) calloc(1,ALLOCSIZE)) != NULL) {
/* initialize the new segment */
newseg->sg_size = anodes;
newseg->sg_next = segs;
segs = newseg;
/* add each new node to the free list */
p = &newseg->sg_nodes[0];
for (n = anodes; n--; ) {
rplacd(p,fnodes);
fnodes = p++;
}
/* update the statistics */
total += (long) ALLOCSIZE;
nnodes += anodes;
nfree += anodes;
nsegs++;
/* return successfully */
return (TRUE);
}
else
return (FALSE);
}
/* livecar - do we need to follow the car? */
LOCAL int livecar(n)
NODE *n;
{
switch (ntype(n)) {
case SUBR:
case FSUBR:
case INT:
case STR:
case FPTR:
return (FALSE);
case SYM:
case LIST:
case OBJ:
return (car(n) != NIL);
default:
printf("bad node type (%d) found during left scan\n",ntype(n));
exit();
}
}
/* livecdr - do we need to follow the cdr? */
LOCAL int livecdr(n)
NODE *n;
{
switch (ntype(n)) {
case SUBR:
case FSUBR:
case INT:
case STR:
case FPTR:
return (FALSE);
case SYM:
case LIST:
case OBJ:
return (cdr(n) != NIL);
default:
printf("bad node type (%d) found during right scan\n",ntype(n));
exit();
}
}
/* stats - print memory statistics */
stats()
{
printf("Nodes: %d\n",nnodes);
printf("Free nodes: %d\n",nfree);
printf("Segments: %d\n",nsegs);
printf("Allocate: %d\n",anodes);
printf("Total: %ld\n",total);
printf("Collections: %d\n",gccalls);
}
/* xlminit - initialize the dynamic memory module */
xlminit()
{
/* initialize our internal variables */
anodes = NNODES;
total = 0L;
nnodes = nsegs = nfree = gccalls = 0;
fnodes = NIL;
segs = NULL;
/* initialize structures that are marked by the collector */
xlstack = xlenv = xlnewenv = oblist = keylist = NIL;
}