⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sbstr.c

📁 操作系统源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	/* Level 4 - write out everything possible */	/* Back up to start of sbstr */	while((sdf = sd->slback) && !sbx_qlk(sdf))		sd = sdf;	if((sdf = sd->slforw) == 0	/* If only 1 blk, ensure on disk */	  || sbx_qlk(sdf))	  {	if(sm = sd->sdmem)		  {	if(sd->sdflags&SD_MOD)		/* If impure, */				sbx_aout(sd, 1);	/* swap out the SD */			sbm_mfree(sm);			sd->sdmem = 0;		  }		return(0);	  }	/* At least two blocks in string.  Set up for flushout. */	sbx_aout(sd, 0);	/* Swapout as much of sbstring as possible */	return(0);lev3:			/* Level 3 - write out more */lev2:			/* Level 2 - write out all impure & small pure */lev1:	if(lev >= 1)	/* Level 1 - merge small impure & small pure */	  {	if(!sm || !sdf) return(0);		while(((smf = sdf->sdmem) && !(sdf->sdflags&SD_LOCKS)		  && (more = smf->smuse + sm->smuse) < SB_BUFSIZ) )		  {	if(sm->smforw != smf			  && more > sm->smlen)		/* If need more rm */			  {	sm = sbm_exp(sm,more);	/* Get it */				if(!sm) return(0);	/* If none, stop */				sd->sdmem = sm;			  }			bcopy(smf->smaddr,			     sm->smaddr + sm->smuse, smf->smuse);			sm->smuse = more;			if(sm->smforw == smf)			  {	sdf->sdmem = 0;				sbm_mmrg(sm);	/* Merge */				if(sm->smlen > more+SB_SLOP)					sbm_mfree(sbm_split(sm, more));					/* Guaranteed to win since mmrg					 * just freed a mem node */			  }			sd->sdflags |= SD_MOD;			if(sdf = sbx_ndel(sdf))				continue;			return(0);		  }	  }	if(lev <= 0)	/* Level 0 - free up large pure blocks */			/* Also merge blocks which are adjacent on disk */	  {	if(sm)		  {	if(sm->smuse == 0)				sd->sdlen = 0;			else if((sd->sdflags&SD_MOD) == 0			    && sm->smuse > 64)			  {	sbm_mfree(sm);				sd->sdmem = 0;				goto lev0adj;			  }			else goto lev0adj;		  }		if(sd->sdlen == 0	/* Free zero blocks */		  && sd->slback)	/* Make sure don't lose list */		  {	sbx_ndel(sd);			if((sd = sdf) == 0)				return(0);			sdf = sd->slforw;		  }	lev0adj:	/* Merge blocks if adjacent on disk */			/* This is common after reading thru large chunks			* of a file but not modifying it much.			*/		if((sd->sdflags&SD_MOD) == 0	/* Pure */		  && sdf && (sdf->sdflags&(SD_LOCKS|SD_MOD)) == 0		  && sd->sdfile && (sd->sdfile == sdf->sdfile)		  && (sd->sdaddr + sd->sdlen) == sdf->sdaddr )		  {	sd->sdlen += sdf->sdlen;			sbx_ndel(sdf);		/* Flush 2nd */			if(sm = sd->sdmem)			  {	sbm_mfree(sm);				sd->sdmem = 0;			  }		  }		return(0);	  }	return(0);}/* SBX_AOUT - output ALL of a hackable sbstring starting at given sdblk. *	Note that code is careful to do things so that an abort at any *	time (e.g. write error) will still leave sbstring in valid state. * Flag value: *	0 - Writes out as many unlocked sdblks as possible, and merges *		so that resulting sdblk (same one pointed to by arg) *		incorporates all stuff written out. *	1 - Writes out single sdblk indicated, whether unlocked or not. *		Doesn't free mem or merge anything; does update physlist *		and flags. *	2 - Writes out all sdblks to specified FD/offset, no mods at all, *		not even to physlist or flags.	Good for saving files *		when something seems wrong.  (How to pass fd/off args?) *		(offset arg not implemented, no need yet; 0 assumed) * Returns 0 if successful, else UNIX system call error number. */sbx_aout(sdp,flag,fd)struct sdblk *sdp;int flag, fd;{	register struct sdblk *sd;	register struct smblk *sm;	register int cnt;	int ifd, ofd, skflg, rem;	chroff inlen;	extern SBMA sbm_lowaddr;	/* Need this from SBM for rndrem */	char buf[SB_BUFSIZ+16];	/* Get buffer space from stack! */				/* Allow extra for word-align reads. */				/* This should be +WDSIZE, but some */				/* C compilers (eg XENIX) can't handle */				/* "sizeof" arith in allocation stmts! */	/* This flag and the two ptrs below are needed because UNIX	 * maintains only one I/O ptr per open file, and we can sometimes	 * be reading from/writing to the swapout file at same time.	 * Using DUP() to get a new FD (to avoid seeking back and forth)	 * won't help since both FD's will use the same I/O ptr!!!	 * Lastly, can't depend on returned value of LSEEK to push/pop	 * ptr, since V6 systems don't implement tell() or lseek() directly.	 * So we have to do it by hand...	 */	int botchflg;	chroff outptr, inptr;	if((sd = sdp)==0) return;	ofd = sbv_tf.sffd;		/* Default output FD */	if(flag==0)	  {	sbx_tset(sbx_qlen(sd),0);/* Find place for whole string */		outptr = sbv_taddr;	/* We'll have to update wrt ptr */	  }	else if (flag==1)	/* Single SD block, so it's reasonable to 				 * try aligning the output with the input. */	  {	if(sm = sd->sdmem)		  {	cnt = rndrem(sm->smaddr - sbm_lowaddr);			sbx_tset((chroff)(sm->smuse),cnt);		  }		else		  {	cnt = rndrem(sd->sdaddr);			sbx_tset(sd->sdlen, cnt);		  }		outptr = sbv_taddr;	/* We'll have to update wrt ptr */	  }	else		/* Outputting a whole sbstring to a file */	  {	ofd = fd;		outptr = 0;	  }	for(; sd;)	  {	if(flag==0 && sbx_qlk(sd))			break;		/* Stop when hit locked sdblk */		if(sm = sd->sdmem)		  {	if(cnt = sm->smuse)				if(write(ofd, sm->smaddr, cnt) != cnt)					return(sbx_err(errno,"Swapout wrt err"));			outptr += cnt;			if(flag==0)			  {	sd->sdmem = 0;	/* Flush the mem used */				sbm_mfree(sm);			  }			inlen = cnt;		  }		else if(inlen = sd->sdlen)		  {	if(sd->sdfile == 0)				return(sbx_err(errno,"Sdfile 0, SD %o",sd));			/* Foo on UNIX */			botchflg = ((ifd = sd->sdfile->sffd) == ofd) ? 1 : 0;			skflg = 1;		/* Always seek first time */			inptr = sd->sdaddr;			/* Efficiency hack - set up for first read so that			 * transfer is word-aligned and terminates at end			 * of a disk block.			 */			rem = rndrem(inptr);		/* Get alignment */			cnt = SB_BUFSIZ - (int)(inptr%SB_BUFSIZ);			while(inlen > 0)			  {				if(inlen < cnt) cnt = inlen;				if(!sbx_rdf(ifd, buf+rem, cnt, skflg, inptr))					return(sbx_err(errno,"Swapout err, SD %o",sd));				/* Further seeks depend on botch setting */				if(skflg = botchflg)				  {	if(lseek(ofd,outptr,0) < 0)						return(sbx_err(errno,							"Swapout sk err"));					inptr += cnt;				  }				if(write(ofd, buf+rem, cnt) != cnt)					return(sbx_err(errno,						"Swapout wrt err"));				outptr += cnt;				inlen -= cnt;				cnt = SB_BUFSIZ; /* Now can use full blocks */				rem = 0;	/* Aligned nicely, too! */			  }			inlen = sd->sdlen;		  }		/* Text written out, now merge block in */		if(flag == 2)			/* No merge if saving file */			goto donxt;		if(sd != sdp)			/* First block? */		  {	sdp->sdlen += inlen;	/* No, simple merge */			sd = sbx_ndel(sd);	/* Flush, get next */			continue;		  }		/* Handle 1st block specially */		if(sd->sdfile		/* Unlink from phys list */		  && sd != sbv_tsd)	/* Don't unlink if self */			sbx_npdel(sd);		sd->sdlen = inlen;		sd->sdfile = &sbv_tf;		sd->sdaddr = sbv_taddr;	/* Set from sbx_tset val */		sd->sdflags &= ~SD_MOD;	/* On disk, no longer modified */		/* Now insert into phys list at specified place */		if(sd == sbv_tsd)	/* If already same place */			goto next;	/* Skip linkin. */		if(sd->sdback = sbv_tsd)		  {	sd->sdforw = sbv_tsd->sdforw;			sd->sdback->sdforw = sd;		  }		else		  {	sd->sdforw = sbv_tf.sfptr1;			sbv_tf.sfptr1 = sd;		  }		if(sd->sdforw)			sd->sdforw->sdback = sd;	next:	if(flag==1)		/* If only doing 1 sdblk, */			break;		/* stop here. */	donxt:	sd = sd->slforw;	/* Done with 1st, get next */	  }	return(0);			/* Win return, no errors */}/* Returns hackable length of a sbstring (ends at EOF or locked block) */chroffsbx_qlen(sdp)struct sdblk *sdp;{	register struct sdblk *sd;	register struct smblk *sm;	chroff len;	len = 0;	for(sd = sdp; sd && !sbx_qlk(sd); sd = sd->slforw)		if(sm = sd->sdmem)			len += (chroff)sm->smuse;		else len += sd->sdlen;	return(len);}/* SBX_TSET - finds a place on temp swapout file big enough to hold *	given # of chars.  Sets SBV_TADDR to that location, as well *	as seeking to it so the next write call will output there. *	This location is guaranteed to have the requested *	byte alignment (0 = word-aligned). */sbx_tset(loff, align)chroff loff;int align;{	register int fd;	if(sbv_tf.sffd <= 0)	  {		/* Must open the temp file! *//* Temporary file mechanism is system-dependent.  Eventually this** will probably require inclusion of a true c-env header file; for the** time being, we can cheat a little by checking O_T20_WILD, which will** be defined by <sys/file.h> on TOPS-20.  Otherwise, we assume we are** on a real Unix.*/#ifdef O_T20_WILD		extern char *tmpnam();	/* Use ANSI function */		fd = open(tmpnam((char *)NULL),				O_RDWR | O_CREAT | O_TRUNC | O_BINARY);		if(fd < 0)			return(sbx_err(0,"Swapout creat err"));		#else /* Real Unix */		static char fcp[] = "/tmp/sbd.XXXXXX";		if((fd = creat(mktemp(fcp),0600)) < 0)			return(sbx_err(0,"Swapout creat err"));		/* Must re-open so that we can both read and write to it */		close(fd);		if((fd = open(fcp,2)) < 0)			return(sbx_err(0,"Swapout open err"));		unlink(fcp);	/* Set so it vanishes when we do */#endif		sbv_tf.sffd = fd;	/* Initialize the sbfile struct */		sbv_tf.sfptr1 = 0;		sbv_ftab[fd] = &sbv_tf;	/* Record in table of all sbfiles */		sbv_taddr = 0;		/* "Return" this value */		return;		/* Ignore alignment for now */	  }	sbv_tsd = sbx_ffnd(&sbv_tf, loff+align, &sbv_taddr);	sbv_taddr += align;	if(lseek(sbv_tf.sffd, sbv_taddr, 0) < 0)		return(sbx_err(0,"Swapout seek err: (%d,%ld,0) %d %s",			sbv_tf.sffd, sbv_taddr, errno, strerror(errno)));}/* SBX_FFND - searches disk list of given file for free space of *	at least size chars.  Note that list must be sorted by ascending *	disk addrs in order for this to work!  If sdaddrs are only *	changed in SBX_SPLIT this will be true. *	Sets "aloc" to disk address for writing (this is guaranteed to *	be word-aligned, for efficiency), and returns SD ptr to *	block which this addr should follow in the physical list.  If ptr *	is 0, it means addr should be 1st thing in list. */struct sdblk *sbx_ffnd(sfp, size, aloc)SBFILE *sfp;chroff size, *aloc;{	register struct sdblk *sd, *sds, *sdl;	chroff cur;	cur = 0;	sds = 0;	sd = sfp->sfptr1;redo:	for(; sd ; sd = (sds=sd)->sdforw)	  {	if(cur < sd->sdaddr)		/* Gap seen? */		  {	if(size <= (sd->sdaddr - cur))	/* Yes, big enuf? */				break;			/* Yup! */		  }					/* No, bump. */		else if(cur >=(sd->sdaddr + sd->sdlen))	/* No gap but chk */			continue;			/* No overlap, ok */		/* Bump to next possible gap. */		cur = sd->sdaddr + sd->sdlen;		cur = (long)rndup(cur);	/* Round up to word boundary! */	  }	*aloc = cur;		/* Return winning addr */	/* Perform verification check -- make sure this really is OK	 * and complain if not.	 If this never blows up, eventually can	 * take the check out.	 */	sdl = sd;	for(sd = sfp->sfptr1; sd; sd = sd->sdforw)	  {	if(cur < sd->sdaddr)		  {	if(size <= (sd->sdaddr - cur))				continue;		  }		else if(cur >= (sd->sdaddr + sd->sdlen))			continue;		sbx_err(0,"FFND blew it, but recovered. SD %o siz %ld",			sd, size);		sd = (sds = sdl)->sdforw;		goto redo;	  }	return(sds);		/* Return ptr to block this addr follows */}sbx_rdf(fd,addr,cnt,skflg,loc)register int fd;char *addr;int skflg;chroff loc;{	register int rres, eres;	long lres;	char *errtyp, *ftyp;	chroff curlen;	errno = 0;	if(skflg && (lres = lseek(fd, (long)loc, 0)) == -1)	  {	errtyp = "Sk err";		goto errhan;	  }	if((rres = read(fd, addr, cnt)) != cnt)	  {	lres = rres;		errtyp = "Rd err";		goto errhan;	  }	return(rres);errhan:				/* Handle read or seek error */	eres = errno;	if(fd == sbv_tf.sffd)	/* See if dealing with swapout file */	  {	ftyp = "(swap)";		curlen = 0;	  }	else {			/* No, normal buffer file. */		ftyp = "";		curlen = sbx_fdlen(fd);		if(sbv_ftab[fd] &&		  (curlen != sbv_ftab[fd]->sflen))	/* File changed? */			if(sbx_rugpull(fd))	/* Yes, handle special case */				return(cnt);	/* Allow "win" return */	  }	sbx_err(0,"%s %d:%s, %ld:(%d%s,%o,%d)=%ld (fl %ld)",			errtyp,	eres, strerror(eres),			loc, fd, ftyp, addr, cnt, lres,			curlen);	return(0);}/* SBX_RUGPULL(fd) - Special routine called when package detects that *	the file indicated by the fd has changed since its original *	opening.  This can happen when a file is over-written by some *	other program (ED, for example). *	This means that all sdblks which reference this fd *	are probably bad.  Pass special error back up to the calling *	program to give it a chance at doing something. *	Extra credit: scan all sdblks and unpurify all which point to this *	file, so as to protect everything we still remember about it. *	Otherwise a GC could flush pure in-core portions. */sbx_rugpull(fd)		/* FD already known to have entry in sbv_ftab */register int fd;{	int sbx_unpur();	/* First scan all sdblks to save what we still have. */	/* This does NOT remove the sdfile pointer, so we can still	 * find blocks that are affected. */	sbm_nfor(SM_DNODS, sizeof(struct sdblk), sbx_unpur, sbv_ftab[fd]);	if((int)sbv_debug == 1 || !sbv_debug)		re

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -