This is vfile.c in view mode; [Download] [Up]
/* Software virtual memory system Copyright (C) 1992 Joseph H. Allen This file is part of JOE (Joe's Own Editor) JOE is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version. JOE is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with JOE; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include "config.h" #include "vs.h" #include "zstr.h" #include "blocks.h" #include "queue.h" #include "path.h" #include "random.h" #include "vfile.h" static VFILE vfiles={{&vfiles,&vfiles}}; /* Known vfiles */ static VPAGE *freepages=0; /* Linked list of free pages */ static VPAGE *htab[HTSIZE]; /* Hash table of page headers */ static long curvalloc=0; /* Amount of memory in use */ static long maxvalloc= ILIMIT; /* Maximum allowed */ char *vbase; /* Data first entry in vheader refers to */ VPAGE **vheaders=0; /* Array of header addresses */ static int vheadsz=0; /* No. entries allocated to vheaders */ void vflsh() { VPAGE *vp; VPAGE *vlowest; long addr; long last; VFILE *vfile; int x; for(vfile=vfiles.link.next; vfile!=&vfiles; vfile=vfile->link.next) { last= -1; loop: addr= MAXLONG; vlowest=0; for(x=0;x!=HTSIZE;x++) for(vp=htab[x];vp;vp=vp->next) if(vp->addr<addr && vp->addr>last && vp->vfile==vfile && (vp->addr>=vfile->size || (vp->dirty && !vp->count))) addr=vp->addr, vlowest=vp; if(vlowest) { if(!vfile->name) vfile->name=mktmp(NULL); if(!vfile->fd) vfile->fd=open(vfile->name,O_RDWR); lseek(vfile->fd,addr,0); if(addr+PGSIZE>vsize(vfile)) { jwrite(vfile->fd,vlowest->data,(int)(vsize(vfile)-addr)); vfile->size=vsize(vfile); } else { jwrite(vfile->fd,vlowest->data,PGSIZE); if(addr+PGSIZE>vfile->size) vfile->size=addr+PGSIZE; } vlowest->dirty=0; last=addr; goto loop; } } } void vflshf(vfile) VFILE *vfile; { VPAGE *vp; VPAGE *vlowest; long addr; int x; loop: addr= MAXLONG; vlowest=0; for(x=0;x!=HTSIZE;x++) for(vp=htab[x];vp;vp=vp->next) if(vp->addr<addr && vp->dirty && vp->vfile==vfile && !vp->count) addr=vp->addr, vlowest=vp; if(vlowest) { if(!vfile->name) vfile->name=mktmp(NULL); if(!vfile->fd) { vfile->fd=open(vfile->name,O_RDWR); } lseek(vfile->fd,addr,0); if(addr+PGSIZE>vsize(vfile)) { jwrite(vfile->fd,vlowest->data,(int)(vsize(vfile)-addr)); vfile->size=vsize(vfile); } else { jwrite(vfile->fd,vlowest->data,PGSIZE); if(addr+PGSIZE>vfile->size) vfile->size=addr+PGSIZE; } vlowest->dirty=0; goto loop; } } char *mema(align,size) { char *z=(char *)malloc(align+size); return z+align-physical(z)%align; } char *vlock(vfile,addr) VFILE *vfile; long addr; { VPAGE *vp, *pp; int x,y; int ofst=(addr&(PGSIZE-1)); addr-=ofst; for(vp=htab[((addr>>LPGSIZE)+(int)vfile)&(HTSIZE-1)];vp;vp=vp->next) if(vp->vfile==vfile && vp->addr==addr) return ++vp->count, vp->data+ofst; if(freepages) { vp=freepages; freepages=vp->next; goto gotit; } if(curvalloc+PGSIZE<=maxvalloc) { vp=(VPAGE *)malloc(sizeof(VPAGE)*INC); if(vp) { vp->data=(char *)mema(PGSIZE,PGSIZE*INC); if(vp->data) { int q; curvalloc+=PGSIZE*INC; if(!vheaders) vheaders=(VPAGE **)malloc((vheadsz=INC)*sizeof(VPAGE *)), vbase=vp->data; else if(physical(vp->data)<physical(vbase)) { VPAGE **t=vheaders; int amnt=(physical(vbase)-physical(vp->data))>>LPGSIZE; vheaders=(VPAGE **)malloc((amnt+vheadsz)*sizeof(VPAGE *)); mcpy(vheaders+amnt,t,vheadsz*sizeof(VPAGE *)); vheadsz+=amnt; vbase=vp->data; free(t); } else if(((physical(vp->data+PGSIZE*INC)-physical(vbase))>>LPGSIZE)>vheadsz) { vheaders=(VPAGE **)realloc(vheaders, (vheadsz=(((physical(vp->data+PGSIZE*INC)-physical(vbase))>>LPGSIZE)))*sizeof(VPAGE *)); } for(q=1;q!=INC;++q) { vp[q].next=freepages; freepages=vp+q; vp[q].data=vp->data+q*PGSIZE; vheader(vp->data+q*PGSIZE)=vp+q; } vheader(vp->data)=vp; goto gotit; } free(vp); vp=0; } } for(y=HTSIZE, x=(random()&(HTSIZE-1));y;x=((x+1)&(HTSIZE-1)), --y) for(pp=(VPAGE *)(htab+x),vp=pp->next;vp;pp=vp, vp=vp->next) if(!vp->count && !vp->dirty) { pp->next=vp->next; goto gotit; } vflsh(); for(y=HTSIZE, x=(random()&(HTSIZE-1));y;x=((x+1)&(HTSIZE-1)), --y) for(pp=(VPAGE *)(htab+x),vp=pp->next;vp;pp=vp, vp=vp->next) if(!vp->count && !vp->dirty) { pp->next=vp->next; goto gotit; } write(2,"vfile: out of memory\n",21); exit(1); gotit: vp->addr=addr; vp->vfile=vfile; vp->dirty=0; vp->count=1; vp->next=htab[((addr>>LPGSIZE)+(int)vfile)&(HTSIZE-1)]; htab[((addr>>LPGSIZE)+(int)vfile)&(HTSIZE-1)]=vp; if(addr<vfile->size) { if(!vfile->fd) { vfile->fd=open(vfile->name,O_RDWR); } lseek(vfile->fd,addr,0); if(addr+PGSIZE>vfile->size) { jread(vfile->fd,vp->data,(int)(vfile->size-addr)); mset(vp->data+vfile->size-addr,0,PGSIZE-(int)(vfile->size-addr)); } else jread(vfile->fd,vp->data,PGSIZE); } else mset(vp->data,0,PGSIZE); return vp->data+ofst; } VFILE *vtmp() { VFILE *new=(VFILE *)malloc(sizeof(VFILE)); new->fd= 0; new->name=0; new->alloc=0; new->size=0; new->left=0; new->lv=0; new->vpage=0; new->flags=1; new->vpage1=0; new->addr= -1; return enqueb(VFILE,link,&vfiles,new); } #ifdef junk VFILE *vopen(name) char *name; { struct stat buf; VFILE *new=(VFILE *)malloc(sizeof(VFILE)); new->name=vsncpy(NULL,0,sz(name)); new->fd=open(name,O_RDWR); if(!new->fd) { fprintf(stderr,"Couldn\'t open file \'%s\'\n",name); free(new); return 0; } fstat(new->fd,&buf); new->size=buf.st_size; new->alloc=new->size; new->left=0; new->lv=0; new->vpage=0; new->flags=0; new->vpage1=0; new->addr= -1; return enqueb(VFILE,link,&vfiles,new); } #endif void vclose(vfile) VFILE *vfile; { VPAGE *vp, *pp; int x; if(vfile->vpage) vunlock(vfile->vpage); if(vfile->vpage1) vunlock(vfile->vpage1); if(vfile->name) { if(vfile->flags) unlink(vfile->name); else vflshf(vfile); vsrm(vfile->name); } if(vfile->fd) close(vfile->fd); free(deque(VFILE,link,vfile)); for(x=0;x!=HTSIZE;x++) for(pp=(VPAGE *)(htab+x), vp=pp->next;vp;) if(vp->vfile==vfile) { pp->next=vp->next; vp->next=freepages; freepages=vp; vp=pp->next; } else pp=vp, vp=vp->next; } #ifdef junk /* this is now broken */ void vlimit(amount) long amount; { VPAGE *vp, *pp; int x,y; maxvalloc=amount; while(curvalloc>maxvalloc) if(freepages) { vp=freepages; freepages=vp->next; free(vp->data); free(vp); curvalloc-=PGSIZE; } else { again: for(y=HTSIZE, x=(random()&(HTSIZE-1));y;x=((x+1)&(HTSIZE-1)), --y) for(pp=(VPAGE *)(htab+x),vp=pp->next;vp;pp=vp, vp=vp->next) if(!vp->count && !vp->dirty) { pp->next=vp->next; free(vp->data); free(vp); if((curvalloc-=PGSIZE)<=maxvalloc) return; goto again; } vflsh(); again1: for(y=HTSIZE, x=(random()&(HTSIZE-1));y;x=((x+1)&(HTSIZE-1)), --y) for(pp=(VPAGE *)(htab+x),vp=pp->next;vp;pp=vp, vp=vp->next) if(!vp->count && !vp->dirty) { pp->next=vp->next; free(vp->data); free(vp); if((curvalloc-=PGSIZE)<=maxvalloc) return; goto again1; } return; } } #endif long valloc(vfile,size) VFILE *vfile; long size; { long start=vsize(vfile); vfile->alloc=start+size; if(vfile->lv) { if(vheader(vfile->vpage)->addr+PGSIZE>vfile->alloc) vfile->lv=PGSIZE-(vfile->alloc-vheader(vfile->vpage)->addr); else vfile->lv=0; } return start; } #ifdef junk void vseek(vfile,addr) VFILE *vfile; long addr; { vfile->alloc=vsize(vfile); if(addr>vfile->alloc) vfile->alloc=addr; if(!vfile->vpage) vfile->vpage=vlock(vfile,addr&~(long)(PGSIZE-1)); else if(vheader(vfile->vpage)->addr!=(addr&~(long)(PGSIZE-1))) { vunlock(vfile->vpage); vfile->vpage=vlock(vfile,addr&~(long)(PGSIZE-1)); } vfile->bufp=vfile->vpage+(addr&(PGSIZE-1)); vfile->left=vfile->vpage+PGSIZE-vfile->bufp; if(vheader(vfile->vpage)->addr+PGSIZE>vfile->alloc) vfile->lv=PGSIZE-(vfile->alloc-vheader(vfile->vpage)->addr); else vfile->lv=0; } int _vrgetc(vfile) VFILE *vfile; { if(vtell(vfile)==0) return MAXINT; vseek(vfile,vtell(vfile)-1); ++vfile->bufp; --vfile->left; return vrgetc(vfile); } int _vgetc(vfile) VFILE *vfile; { if(vtell(vfile)==vsize(vfile)) return MAXINT; vseek(vfile,vtell(vfile)); return vgetc(vfile); } int nmvgetc(v) VFILE *v; { return vgetc(v); } int _vputc(vfile,c) VFILE *vfile; char c; { vseek(vfile,vtell(vfile)); return vputc(vfile,c); } short vgetw(vfile) VFILE *vfile; { short w; if(vtell(vfile)+2>vsize(vfile)) return -1; w=vgetc(vfile); w+=((short)vgetc(vfile)<<8); return w; } short vputw(vfile,w) VFILE *vfile; short w; { vputc(vfile,w); vputc(vfile,w>>8); return w; } long vgetl(vfile) VFILE *vfile; { long w; if(vtell(vfile)+4>vsize(vfile)) return -1; w=vgetc(vfile); w+=((long)vgetc(vfile)<<8); w+=((long)vgetc(vfile)<<16); w+=((long)vgetc(vfile)<<24); return w; } long vputl(vfile,w) VFILE *vfile; long w; { vputc(vfile,w); vputc(vfile,w>>8); vputc(vfile,w>>16); vputc(vfile,w>>24); return w; } int _rc(vfile,addr) VFILE *vfile; long addr; { if(vfile->vpage1) vunlock(vfile->vpage1); vfile->vpage1=vlock(vfile,vfile->addr=(addr&~(long)(PGSIZE-1))); return rc(vfile,addr); } int _wc(vfile,addr,c) VFILE *vfile; long addr; char c; { if(addr+1>vsize(vfile)) valloc(vfile,addr+1-vsize(vfile)); if(vfile->vpage1) vunlock(vfile->vpage1); vfile->vpage1=vlock(vfile,vfile->addr=(addr&~(long)(PGSIZE-1))); return wc(vfile,addr,c); } short rw(vfile,addr) VFILE *vfile; long addr; { short c; if(addr+2>vsize(vfile)) return -1; c=rc(vfile,addr); c+=((short)rc(vfile,addr+1)<<8); return c; } short ww(vfile,addr,c) VFILE *vfile; long addr; short c; { if(addr+2>vsize(vfile)) valloc(vfile,addr+2-vsize(vfile)); wc(vfile,addr,c); wc(vfile,addr+1,c>>8); return c; } long rl(vfile,addr) VFILE *vfile; long addr; { long c; if(addr+4>vsize(vfile)) return -1; c=rc(vfile,addr); c+=((long)rc(vfile,addr+1)<<8); c+=((long)rc(vfile,addr+2)<<16); c+=((long)rc(vfile,addr+3)<<24); return c; } long wl(vfile,addr,c) VFILE *vfile; long addr; long c; { if(addr+4>vsize(vfile)) valloc(vfile,addr+4-vsize(vfile)); wc(vfile,addr,c); wc(vfile,addr+1,c>>8); wc(vfile,addr+2,c>>16); wc(vfile,addr+3,c>>24); return c; } void vread(v,blk,size) VFILE *v; char *blk; int size; { long addr=vtell(v); char *src; int x; while(size) { src=vlock(v,addr); x=PGSIZE-(addr&(PGSIZE-1)); if(x>=size) { vseek(v,addr+size); mcpy(blk,src,size); vunlock(src); return; } size-=x; addr+=x; mcpy(blk,src,x); blk+=x; vunlock(src); } vseek(v,addr); } void vwrite(v,blk,size) VFILE *v; char *blk; int size; { long addr=vtell(v); char *src; int x; if(addr+size>vsize(v)) valloc(v,addr+size-vsize(v)); while(size) { src=vlock(v,addr); x=PGSIZE-(addr&(PGSIZE-1)); if(x>=size) { vseek(v,addr+size); mcpy(src,blk,size); vchanged(src); vunlock(src); return; } size-=x; addr+=x; mcpy(src,blk,x); blk+=x; vchanged(src); vunlock(src); } vseek(v,addr); } /* Write zstring to vfile */ void vputs(v,s) VFILE *v; char *s; { while(*s) vputc(v,*s), ++s; } /* Read a line from a file. Remove '\n' if there was any */ char *vgets(v,s) VFILE *v; char *s; { char *b, *a, *x, *y; int cnt; /* Return with NULL if at end of file */ if(vtell(v)==vsize(v)) { vsrm(s); return 0; } /* Create string if it doesn't exist */ if(!s) s=vsmk(80); /* Zero string length */ sLen(s)=0; loop: /* Set b to end of string, a to page pointer, and cnt to min which ever * (string or page) has the least space left */ b=s+sLen(s); a=v->bufp; cnt=Imin(sSIZ(s)-sLen(s),v->left-v->lv); /* Copy until \n is found or until page or buffer out of space */ if(cnt>=16) do { if((b[0]=a[0])=='\n') { a+=1; b+=1; goto ovr; } if((b[1]=a[1])=='\n') { a+=2; b+=2; cnt-=1; goto ovr; } if((b[2]=a[2])=='\n') { a+=3; b+=3; cnt-=2; goto ovr; } if((b[3]=a[3])=='\n') { a+=4; b+=4; cnt-=3; goto ovr; } if((b[4]=a[4])=='\n') { a+=5; b+=5; cnt-=4; goto ovr; } if((b[5]=a[5])=='\n') { a+=6; b+=6; cnt-=5; goto ovr; } if((b[6]=a[6])=='\n') { a+=7; b+=7; cnt-=6; goto ovr; } if((b[7]=a[7])=='\n') { a+=8; b+=8; cnt-=7; goto ovr; } if((b[8]=a[8])=='\n') { a+=9; b+=9; cnt-=8; goto ovr; } if((b[9]=a[9])=='\n') { a+=10; b+=10; cnt-=9; goto ovr; } if((b[10]=a[10])=='\n') { a+=11; b+=11; cnt-=10; goto ovr; } if((b[11]=a[11])=='\n') { a+=12; b+=12; cnt-=11; goto ovr; } if((b[12]=a[12])=='\n') { a+=13; b+=13; cnt-=12; goto ovr; } if((b[13]=a[13])=='\n') { a+=14; b+=14; cnt-=13; goto ovr; } if((b[14]=a[14])=='\n') { a+=15; b+=15; cnt-=14; goto ovr; } if((b[15]=a[15])=='\n') { a+=16; b+=16; cnt-=15; goto ovr; } } while(a+=16, b+=16, (cnt-=16)>=16); /* x=a, y=b; a+=cnt-15; b+=cnt-15; switch(cnt) { case 15: if((b[0]=a[0])=='\n') { a+=1; b+=1; goto zif; } case 14: if((b[1]=a[1])=='\n') { a+=2; b+=2; goto zif; } case 13: if((b[2]=a[2])=='\n') { a+=3; b+=3; goto zif; } case 12: if((b[3]=a[3])=='\n') { a+=4; b+=4; goto zif; } case 11: if((b[4]=a[4])=='\n') { a+=5; b+=5; goto zif; } case 10: if((b[5]=a[5])=='\n') { a+=6; b+=6; goto zif; } case 9: if((b[6]=a[6])=='\n') { a+=7; b+=7; goto zif; } case 8: if((b[7]=a[7])=='\n') { a+=8; b+=8; goto zif; } case 7: if((b[8]=a[8])=='\n') { a+=9; b+=9; goto zif; } case 6: if((b[9]=a[9])=='\n') { a+=10; b+=10; goto zif; } case 5: if((b[10]=a[10])=='\n'){ a+=11; b+=11; goto zif; } case 4: if((b[11]=a[11])=='\n'){ a+=12; b+=12; goto zif; } case 3: if((b[12]=a[12])=='\n'){ a+=13; b+=13; goto zif; } case 2: if((b[13]=a[13])=='\n'){ a+=14; b+=14; goto zif; } case 1: if((b[14]=a[14])=='\n'){ a+=15; b+=15; goto zif; } } a=x+cnt, b=y+cnt; cnt=0; goto ovr; zif: cnt-=a-x-1; */ if(cnt) do if((*b++=*a++)=='\n') break; while(--cnt); ovr: /* Update string and page data */ sLen(s)=b-s; v->left-=a-v->bufp; v->bufp=a; if(!cnt) if(vtell(v)==vsize(v)) b[0]=0; else { if(sLen(s)==sSiz(s)) s=vsensure(s,sLen(s)+(sLen(s)>>1)+16); if(!v->left) vseek(v,vtell(v)); goto loop; } else b[-1]=0; return s; } #endif
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.