Ausam/sys/ken/pipe.c

Find at most related files.
including files from this version of Unix.

#
/*
 */

#include "../defines.h"
#include "../param.h"
#ifdef	AUSAML
#include "../lnode.h"
#endif	AUSAML
#include "../systm.h"
#include "../file.h"
#include "../user.h"
#include "../inode.h"
#include "../reg.h"

/*
 * Max allowable buffering per pipe.
 * This is also the max size of the
 * file created to implement the pipe.
 * If this size is bigger than 4096,
 * pipes will be implemented in LARG
 * files, which is probably not good.
 */
#define	PIPSIZ	4096

/*
 * The sys-pipe entry.
 * Allocate an inode on the root device.
 * Allocate 2 file structures.
 * Put it all together with flags.
 */
pipe()
{
	register *ip, *rf, *wf;
	int r;

	ip = ialloc(rootdev);
	if(ip == NULL)
		return;
	rf = falloc();
	if(rf == NULL) {
		iput(ip);
		return;
	}
	r = u.u_ar0[R0];
	wf = falloc();
	if(wf == NULL) {
		rf->f_count = 0;
		u.u_ofile[r] = NULL;
		iput(ip);
		return;
	}
	u.u_ar0[R1] = u.u_ar0[R0];
	u.u_ar0[R0] = r;
	wf->f_flag = FWRITE|FPIPE;
	wf->f_inode = ip;
	rf->f_flag = FREAD|FPIPE;
	rf->f_inode = ip;
	ip->i_count = 2;
	ip->i_flag = IACC|IUPD|IPIPE;	/* fix038 */
	ip->i_mode = IALLOC;
}

#ifdef	CIRCULAR_PIPE
/*
 *	Circular read from a pipe.
 */
readp(fp)
register *fp;
{
	register *ip, r;
	int ct;

	ip = fp->f_inode;
	do
	{
		if((ct = u.u_count) == 0)
			return;
		plock(ip);

		/*
		 * If there is nothing there sleep and try again.
		 */

		while((r = ip->i_size1) == 0)
		{
			/*
			 * If there is not a read and a write pointer
			 * then return without reading.
			 */

			prele(ip);
			if(ip->i_count < 2)
				return;
			ip->i_mode =| IREAD;
			sleep(ip+2, PPIPE);
			plock(ip);
		}
		ip->i_size1 = min(fp->f_offset.loint + r, PIPSIZ);
		u.u_offset = fp->f_offset.loint;
		readi(ip);
		ip->i_size1 = r - (ct - u.u_count);

		/*
		 * If the read pointer has reached the end of the
		 * pipe buffer reset it to the front.
		 */

		if((fp->f_offset.loint = u.u_offset.loint) == PIPSIZ)
			fp->f_offset.loint = 0;

		/*
		 * If the write proccess was sleeping wake it up.
		 */

		if(ip->i_mode & IWRITE)
		{
			ip->i_mode =& ~IWRITE;
			wakeup(ip+1);
		}

		prele(ip);
	}
	while(fp->f_offset.loint == 0 && ip->i_size1 != 0 && u.u_error == 0);
}
#else	CIRCULAR_PIPE
/*
 * Read call directed to a pipe.
 */
readp(fp)
int *fp;
{
	register *rp, *ip;

	rp = fp;
	ip = rp->f_inode;

loop:
	/*
	 * Very conservative locking.
	 */

	plock(ip);

	/*
	 * If nothing in the pipe wait.
	 */

	if( ip->i_size1 == 0 ) {			/* fix025 */
		/*
		 * If there are not both reader and
		 * writer active, return without
		 * satisfying read.
		 */
		prele(ip);
		if(ip->i_count < 2)
			return;
		ip->i_mode =| IREAD;
		sleep(ip+2, PPIPE);
		goto loop;
	}

	/*
	 * Read and return
	 */

	u.u_offset = rp->f_offset.loint.unsignd; /* fix000 */
	readi(ip);
	rp->f_offset.loint = u.u_offset.loint; /* fix000 */
	/*
	 * If reader has caught up with writer,			fix025
	 * reset offset and size to zero.			fix025
	 */
	if( rp->f_offset.loint == ip->i_size1 )			/* fix025 */
	{
		rp->f_offset.loint = 0;				/* fix025 */
		ip->i_size1 = 0;				/* fix025 */
		if( ip->i_mode & IWRITE )			/* fix025 */
		{
			ip->i_mode =& ~IWRITE;			/* fix025 */
			wakeup(ip+1);				/* fix025 */
		}
	}
	prele(ip);
}
#endif	CIRCULAR_PIPE

#ifdef	CIRCULAR_PIPE
/*
 * Circular write on a pipe.
 */
writep(fp)
register *fp;
{
	register *ip, c;
	int sz;

	ip = fp->f_inode;
	c = u.u_count;
	while(c && u.u_error == 0)
	{
		plock(ip);

		/*
		 * If there is not both a read and a write pointer
		 * set the broken pipe error and return.
		 */

		if(ip->i_count < 2)
		{
			prele(ip);
			u.u_error = EPIPE;
			psignal(u.u_procp, SIGPIPE);
			return;
		}

		/*
		 * If the pipe is already full wait till
		 * some of it is read.
		 */

		if((sz = ip->i_size1) == PIPSIZ)
		{
			prele(ip);
			ip->i_mode =| IWRITE;
			sleep(ip+1, PPIPE);
			continue;
		}
		u.u_offset = fp->f_offset.loint;
		u.u_count = min(c, PIPSIZ - max(fp->f_offset.loint, sz));
		c =- u.u_count;
		sz =+ u.u_count;
		writei(ip);
		ip->i_size1 = sz;
		if((fp->f_offset.loint = u.u_offset.loint) == PIPSIZ)
			fp->f_offset.loint = 0;
		prele(ip);

		/*
		 * If the read proccess had been waiting wake it up.
		 */

		if(ip->i_mode & IREAD)
		{
			ip->i_mode =& ~IREAD;
			wakeup(ip+2);
		}
	}
}
#else	CIRCULAR_PIPE
/*
 * Write call directed to a pipe.
 */
writep(fp)
{
	register *rp, *ip, c;

	rp = fp;
	ip = rp->f_inode;
	c = u.u_count;

loop:

	/*
	 * If all done, return.
	 */

	plock(ip);
	if(c == 0) {
		prele(ip);
		u.u_count = 0;
		return;
	}

	/*
	 * If there are not both read and
	 * write sides of the pipe active,
	 * return error and signal too.
	 */

	if(ip->i_count < 2) {
		prele(ip);
		u.u_error = EPIPE;
		psignal(u.u_procp, SIGPIPE);
		return;
	}

	/*
	 * If the pipe is full,
	 * wait for reads to deplete
	 * and truncate it.
	 */

	if(ip->i_size1 >= PIPSIZ) {		/* fix025 */
		ip->i_mode =| IWRITE;
		prele(ip);
		sleep(ip+1, PPIPE);
		goto loop;
	}

	/*
	 * Write what is possible and
	 * loop back.
	 * If writing less than PIPSIZ, it always goes.		fix025
	 * One can therefore get a file > PIPSIZ if write	fix025
	 * sizes do not divide PIPSIZ.				fix025
	 */

	u.u_offset = ip->i_size1.unsignd; /* fix000 */
	u.u_count = min(c, PIPSIZ);	/* fix025 */
	c =- u.u_count;
	writei(ip);
	prele(ip);
	if(ip->i_mode&IREAD) {
		ip->i_mode =& ~IREAD;
		wakeup(ip+2);
	}
	goto loop;
}
#endif	CIRCULAR_PIPE

/*
 * Lock a pipe.
 * If its already locked,
 * set the WANT bit and sleep.
 */
plock(ip)
register *ip;
{
	while(ip->i_flag&ILOCK) {
		ip->i_flag =| IWANT;
		sleep(ip, PPIPE);
	}
	ip->i_flag =| ILOCK;
}

/*
 * Unlock a pipe.
 * If WANT bit is on,
 * wakeup.
 * This routine is also used
 * to unlock inodes in general.
 */
prele(ip)
register *ip;
{
	ip->i_flag =& ~ILOCK;
	if(ip->i_flag&IWANT) {
		ip->i_flag =& ~IWANT;
		wakeup(ip);
	}
}