home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.barnyard.co.uk
/
2015.02.ftp.barnyard.co.uk.tar
/
ftp.barnyard.co.uk
/
cpm
/
walnut-creek-CDROM
/
CPM
/
LANGUAGS
/
XLISP
/
XLISP12.ARK
/
XLDMEM.C
< prev
next >
Wrap
Text File
|
1985-02-19
|
7KB
|
342 lines
/* xldmem - xlisp dynamic memory management routines */
#ifdef AZTEC
#include "stdio.h"
#else
#include <stdio.h>
#endif
#include "xlisp.h"
/* useful definitions */
#define ALLOCSIZE (sizeof(struct segment) + (anodes-1) * sizeof(struct node))
/* memory segment structure definition */
struct segment {
int sg_size;
struct segment *sg_next;
struct node sg_nodes[1];
};
/* external variables */
extern struct node *oblist;
extern struct node *xlstack;
extern struct node *xlenv;
/* external procedures */
extern char *malloc();
extern char *calloc();
/* local variables */
int anodes,nnodes,nsegs,nfree,gccalls;
static struct segment *segs;
static struct node *fnodes;
/* newnode - allocate a new node */
struct node *newnode(type)
int type;
{
struct node *nnode;
/* get a free node */
if ((nnode = fnodes) == NULL) {
gc();
if ((nnode = fnodes) == NULL)
xlfail("insufficient node space");
}
/* unlink the node from the free list */
fnodes = nnode->n_right;
nfree -= 1;
/* initialize the new node */
nnode->n_type = type;
nnode->n_right = NULL;
/* 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");
}
/* 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;
{
free(str);
}
/* gc - garbage collect */
gc()
{
struct node *p;
/* mark all accessible nodes */
mark(oblist);
mark(xlenv);
/* mark the evaluation stack */
for (p = xlstack; p; p = p->n_listnext)
mark(p->n_listvalue);
/* sweep memory collecting all unmarked nodes */
sweep();
/* if there's still nothing available, allocate more memory */
if (fnodes == NULL)
addseg();
/* count the gc call */
gccalls += 1;
}
/* mark - mark all accessible nodes */
LOCAL mark(ptr)
struct node *ptr;
{
struct node *this,*prev,*tmp;
/* just return on null */
if (ptr == NULL)
return;
/* initialize */
prev = NULL;
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 (left(this)) {
this->n_flags |= LEFT;
tmp = prev;
prev = this;
this = prev->n_left;
prev->n_left = tmp;
}
else if (right(this)) {
this->n_flags &= ~LEFT;
tmp = prev;
prev = this;
this = prev->n_right;
prev->n_right = tmp;
}
else
break;
}
}
/* backup to a point where we can continue descending */
while (TRUE) {
/* check for termination condition */
if (prev == NULL)
return;
/* check for coming from the left side */
if (prev->n_flags & LEFT)
if (right(prev)) {
prev->n_flags &= ~LEFT;
tmp = prev->n_left;
prev->n_left = this;
this = prev->n_right;
prev->n_right = tmp;
break;
}
else {
tmp = prev;
prev = tmp->n_left;
tmp->n_left = this;
this = tmp;
}
/* came from the right side */
else {
tmp = prev;
prev = tmp->n_right;
tmp->n_right = this;
this = tmp;
}
}
}
}
/* sweep - sweep all unmarked nodes and add them to the free list */
LOCAL sweep()
{
struct segment *seg;
struct node *p;
int n;
/* empty the free list */
fnodes = NULL;
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 (p->n_type) {
case STR:
if (p->n_strtype == DYNAMIC && p->n_str != NULL)
strfree(p->n_str);
break;
}
p->n_type = FREE;
p->n_flags = 0;
p->n_left = NULL;
p->n_right = fnodes;
fnodes = p;
nfree += 1;
}
else
p->n_flags &= ~(MARK | LEFT);
}
}
/* addseg - add a segment to the available memory */
int addseg()
{
struct segment *newseg;
struct 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--; ) {
p->n_right = fnodes;
fnodes = p++;
}
/* update the statistics */
nnodes += anodes;
nfree += anodes;
nsegs += 1;
/* return successfully */
return (TRUE);
}
else
return (FALSE);
}
/* left - check for a left sublist */
LOCAL int left(n)
struct node *n;
{
switch (n->n_type) {
case SUBR:
case FSUBR:
case INT:
case STR:
case FPTR:
return (FALSE);
case SYM:
case LIST:
case OBJ:
return (n->n_left != NULL);
default:
printf("bad node type (%d) found during left scan\n",n->n_type);
exit();
}
}
/* right - check for a right sublist */
LOCAL int right(n)
struct node *n;
{
switch (n->n_type) {
case SUBR:
case FSUBR:
case INT:
case STR:
case FPTR:
return (FALSE);
case SYM:
case LIST:
case OBJ:
return (n->n_right != NULL);
default:
printf("bad node type (%d) found during right scan\n",n->n_type);
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("Collections: %d\n",gccalls);
}
/* xlminit - initialize the dynamic memory module */
xlminit()
{
/* initialize our internal variables */
anodes = NNODES;
nnodes = nsegs = nfree = gccalls = 0;
segs = fnodes = NULL;
/* initialize structures that are marked by the collector */
xlstack = xlenv = oblist = NULL;
}