diff options
Diffstat (limited to 'xlisp/xlimage.c')
-rw-r--r-- | xlisp/xlimage.c | 407 |
1 files changed, 407 insertions, 0 deletions
diff --git a/xlisp/xlimage.c b/xlisp/xlimage.c new file mode 100644 index 0000000..f26075a --- /dev/null +++ b/xlisp/xlimage.c @@ -0,0 +1,407 @@ +/* xlimage - xlisp memory image save/restore functions */ +/* Copyright (c) 1985, by David Michael Betz + All Rights Reserved + Permission is granted for unrestricted non-commercial use */ + +#include "stdlib.h" +#include "string.h" +#include "xlisp.h" + +#ifdef SAVERESTORE + +/* external variables */ +extern LVAL obarray,s_gchook,s_gcflag; +extern long nnodes,nfree,total; +extern int anodes,nsegs,gccalls; +extern struct segment *segs,*lastseg,*fixseg,*charseg; +extern XLCONTEXT *xlcontext; +extern LVAL fnodes; +extern struct xtype_desc_struct desc_table[NTYPES]; + +/* local variables */ +static OFFTYPE off,foff; +static FILE *fp; + +/* forward declarations */ +LOCAL OFFTYPE readptr(void); +LOCAL OFFTYPE cvoptr(LVAL p); +LOCAL LVAL cviptr(OFFTYPE o); +LOCAL void writeptr(OFFTYPE off); +LOCAL void setoffset(void); +LOCAL void writenode(LVAL node); +LOCAL void freeimage(void); +LOCAL void readnode(int type, LVAL node); + + +/* xlisave - save the memory image */ +int xlisave(char *fname) +{ + char fullname[STRMAX+1]; + unsigned char *cp; + SEGMENT *seg; + int n,i,max; + LVAL p; + + /* default the extension */ + if (needsextension(fname)) { + strcpy(fullname,fname); + strcat(fullname,".wks"); + fname = fullname; + } + + /* open the output file */ + if ((fp = osbopen(fname,"w")) == NULL) + return (FALSE); + + /* first call the garbage collector to clean up memory */ + gc(); + + /* invalidate extern type descriptor symbol caches */ + inval_caches(); + + /* write out the pointer to the *obarray* symbol */ + writeptr(cvoptr(obarray)); + + /* setup the initial file offsets */ + off = foff = (OFFTYPE)2; + + /* write out all nodes that are still in use */ + for (seg = segs; seg != NULL; seg = seg->sg_next) { + p = &seg->sg_nodes[0]; + for (n = seg->sg_size; --n >= 0; ++p, off += 2) + switch (ntype(p)) { + case FREE_NODE: + break; + case CONS: + case USTREAM: + setoffset(); + osbputc(p->n_type,fp); + writeptr(cvoptr(car(p))); + writeptr(cvoptr(cdr(p))); + foff += 2; + break; + case EXTERN: + setoffset(); + osbputc(EXTERN, fp); +/* printf("saving EXTERN p = %x, desc %x\n", p, getdesc(p)); fflush(stdout);*/ + writeptr((OFFTYPE) (getdesc(p) - desc_table)); /* write type index */ + writeptr((OFFTYPE) 0); /* pointer gets reconstructed on input */ + foff += 2; + break; + default: + setoffset(); + writenode(p); + break; + } + } + + /* write the terminator */ + osbputc(FREE_NODE,fp); + writeptr((OFFTYPE)0); + + /* write out data portion of SYMBOL/VECTOR/OBJECT/STRING/CLOSURE nodes */ + for (seg = segs; seg != NULL; seg = seg->sg_next) { + p = &seg->sg_nodes[0]; + for (n = seg->sg_size; --n >= 0; ++p) + switch (ntype(p)) { + case SYMBOL: + case OBJECT: + case VECTOR: + case CLOSURE: + max = getsize(p); + for (i = 0; i < max; ++i) + writeptr(cvoptr(getelement(p,i))); + break; + case STRING: + max = getslength(p); + for (cp = getstring(p); --max >= 0; ) + osbputc(*cp++,fp); + break; + case EXTERN: +/* printf("saving extern data for p = %x\n", p);*/ + (*(getdesc(p)->save_meth))(fp, getinst(p)); + break; + } + } + + /* close the output file */ + osclose(fp); + + /* return successfully */ + return (TRUE); +} + +/* xlirestore - restore a saved memory image */ +int xlirestore(char *fname) +{ + extern FUNDEF funtab[]; + char fullname[STRMAX+1]; + unsigned char *cp; + int n,i,max,type; + SEGMENT *seg; + LVAL p; + + /* default the extension */ + if (needsextension(fname)) { + strcpy(fullname,fname); + strcat(fullname,".wks"); + fname = fullname; + } + + /* open the file */ + if ((fp = osbopen(fname,"r")) == NULL) + return (FALSE); + + /* free the old memory image */ + freeimage(); + + /* initialize */ + off = (OFFTYPE)2; + total = nnodes = nfree = 0L; + fnodes = NIL; + segs = lastseg = NULL; + nsegs = gccalls = 0; + xlenv = xlfenv = xldenv = s_gchook = s_gcflag = NIL; + xlstack = xlstkbase + EDEPTH; + xlcontext = NULL; + + /* create the fixnum segment */ + if ((fixseg = newsegment(SFIXSIZE)) == NULL) + xlfatal("insufficient memory - fixnum segment"); + + /* create the character segment */ + if ((charseg = newsegment(CHARSIZE)) == NULL) + xlfatal("insufficient memory - character segment"); + + /* read the pointer to the *obarray* symbol */ + obarray = cviptr(readptr()); + + /* read each node */ + while ((type = osbgetc(fp)) >= 0) + switch (type) { + case FREE_NODE: + if ((off = readptr()) == (OFFTYPE)0) + goto done; + break; + case CONS: + case USTREAM: + p = cviptr(off); + p->n_type = type; + p->n_flags = 0; + rplaca(p,cviptr(readptr())); + rplacd(p,cviptr(readptr())); + off += 2; + break; + case EXTERN: + p = cviptr(off); +/* printf("reading extern node p = %x\n", p);*/ + p->n_type = EXTERN; + setdesc(p, desc_table + (int) readptr()); +/* printf("type desc is %x\n", getdesc(p));*/ + setinst(p, (unsigned char *) readptr()); +/* printf("initial inst is %x\n", getinst(p));*/ + off += 2; + break; + default: + readnode(type,cviptr(off)); + off += 2; + break; + } +done: + + /* read the data portion of SYMBOL/VECTOR/OBJECT/STRING/CLOSURE nodes */ + for (seg = segs; seg != NULL; seg = seg->sg_next) { + p = &seg->sg_nodes[0]; + for (n = seg->sg_size; --n >= 0; ++p) + switch (ntype(p)) { + case SYMBOL: + case OBJECT: + case VECTOR: + case CLOSURE: + max = getsize(p); + if ((p->n_vdata = (LVAL *)malloc(max * sizeof(LVAL))) == NULL) + xlfatal("insufficient memory - vector"); + total += (long)(max * sizeof(LVAL)); + for (i = 0; i < max; ++i) + setelement(p,i,cviptr(readptr())); + break; + case STRING: + max = getslength(p); + if ((p->n_string = (unsigned char *)malloc(max)) == NULL) + xlfatal("insufficient memory - string"); + total += (long)max; + for (cp = getstring(p); --max >= 0; ) + *cp++ = osbgetc(fp); + break; + case STREAM: + setfile(p,NULL); + break; + case SUBR: + case FSUBR: + p->n_subr = funtab[getoffset(p)].fd_subr; + break; + case EXTERN: +/* printf("restoring extern %x\n", p); fflush(stdout); */ + setinst(p, (*(getdesc(p)->restore_meth))(fp)); + break; + } + } + + /* close the input file */ + osclose(fp); + + /* collect to initialize the free space */ + gc(); + + /* lookup all of the symbols the interpreter uses */ + xlsymbols(); + + /* return successfully */ + return (TRUE); +} + +/* freeimage - free the current memory image */ +LOCAL void freeimage(void) +{ + SEGMENT *seg,*next; + FILE *fp; + LVAL p; + int n; + + /* free the data portion of SYMBOL/VECTOR/OBJECT/STRING nodes */ + for (seg = segs; seg != NULL; seg = next) { + p = &seg->sg_nodes[0]; + for (n = seg->sg_size; --n >= 0; ++p) + switch (ntype(p)) { + case SYMBOL: + case OBJECT: + case VECTOR: + case CLOSURE: + if (p->n_vsize) + free(p->n_vdata); + break; + case STRING: + if (getslength(p)) + free((void *) getstring(p)); + break; + case STREAM: + if ((fp = getfile(p)) && (fp != stdin && fp != stdout && fp != STDERR)) + osclose(getfile(p)); + break; + } + next = seg->sg_next; + free((void *) seg); + } +} + +/* setoffset - output a positioning command if nodes have been skipped */ +LOCAL void setoffset(void) +{ + if (off != foff) { + osbputc(FREE_NODE,fp); + writeptr(off); + foff = off; + } +} + +/* writenode - write a node to a file */ +LOCAL void writenode(LVAL node) +{ + char *p = (char *)&node->n_info; + int n = sizeof(union ninfo); + osbputc(node->n_type,fp); + while (--n >= 0) + osbputc(*p++,fp); + foff += 2; +} + +/* writeptr - write a pointer to a file */ +LOCAL void writeptr(OFFTYPE off) +{ + char *p = (char *)&off; + int n = sizeof(OFFTYPE); + while (--n >= 0) + osbputc(*p++,fp); +} + +/* readnode - read a node */ +LOCAL void readnode(int type, LVAL node) +{ + char *p = (char *)&node->n_info; + int n = sizeof(union ninfo); + node->n_type = type; + node->n_flags = 0; + while (--n >= 0) + *p++ = osbgetc(fp); +} + +/* readptr - read a pointer */ +LOCAL OFFTYPE readptr(void) +{ + OFFTYPE off; + char *p = (char *)&off; + int n = sizeof(OFFTYPE); + while (--n >= 0) + *p++ = osbgetc(fp); + return (off); +} + +/* cviptr - convert a pointer on input */ +LOCAL LVAL cviptr(OFFTYPE o) +{ + OFFTYPE off = (OFFTYPE)2; + SEGMENT *seg; + + /* check for nil */ + if (o == (OFFTYPE)0) + return ((LVAL)o); + + /* compute a pointer for this offset */ + for (seg = segs; seg != NULL; seg = seg->sg_next) { + if (o >= off && o < off + (OFFTYPE)(seg->sg_size << 1)) + return (seg->sg_nodes + ((int)(o - off) >> 1)); + off += (OFFTYPE)(seg->sg_size << 1); + } + + /* create new segments if necessary */ + for (;;) { + + /* create the next segment */ + if ((seg = newsegment(anodes)) == NULL) + xlfatal("insufficient memory - segment"); + + /* check to see if the offset is in this segment */ + if (o >= off && o < off + (OFFTYPE)(seg->sg_size << 1)) + return (seg->sg_nodes + ((int)(o - off) >> 1)); + off += (OFFTYPE)(seg->sg_size << 1); + } +} + +/* cvoptr - convert a pointer on output */ +LOCAL OFFTYPE cvoptr(LVAL p) +{ + OFFTYPE off = (OFFTYPE)2; + SEGMENT *seg; + + /* check for nil and small fixnums */ + if (p == NIL) + return ((OFFTYPE)p); + + /* compute an offset for this pointer */ + for (seg = segs; seg != NULL; seg = seg->sg_next) { + if (CVPTR(p) >= CVPTR(&seg->sg_nodes[0]) && + CVPTR(p) < CVPTR(&seg->sg_nodes[0] + seg->sg_size)) + return (off + (OFFTYPE)((p - seg->sg_nodes) << 1)); + off += (OFFTYPE)(seg->sg_size << 1); + } + + /* pointer not within any segment */ + xlerror("bad pointer found during image save",p); + /* this point will never be reached because xlerror() does a + longjmp(). The return is added to avoid false positive + error messages from static analyzers and compilers */ + return ((OFFTYPE)NIL); +} + +#endif + |