BBN-V6/ken/pipe.c
#
/*
*/
#include "../h/param.h"
#include "../h/systm.h"
#include "../h/user.h"
#include "../h/inode.h"
#include "../h/file.h"
#include "../h/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 1024
#define BLKSIZE 512
#define PMAXPAGE 8
/*
* 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;
ip->i_mode = IALLOC|IPIPE;
}
/*
* Read call directed to a pipe.
* Modified 12/5/78 (BBN:mek) to avoid awakei if called from portread
*/
readp(fp,flag)
int *fp,flag;
{
register *rp, *ip;
int i,curpage;
rp = fp;
ip = rp->f_inode;
loop:
/*
* Very conservative locking.
*/
plock(ip);
if(ip->i_size1 == 0) {
/* Pipe is empty */
if (ip->i_flag & IEOFP) /* rand:bobg--EOF on pipe */
{
ip->i_flag =& ~IEOFP; /* `read' the EOF */
wakeup(ip+3); /* allow further writes */
prele(ip); /* didn't even need it! */
return; /* EOF simulated */
}
/*
* 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[0] = 0;
u.u_offset[1] = rp->f_offset[1];
readi(ip);
/* BBN: mek (4/30/79) - free all unneeded buffers.
Moved from below */
curpage = u.u_offset[1]/BLKSIZE;
for ( i =0; i < curpage; i++ ) bdfree(ip,i);
/* Rand change to reset at end of read instead of beginning *
* Some of this code has been moved from above.
*
* If the head (read) has caught up with
* the tail (write), reset both to 0.
*/
if ((rp->f_offset[1] = u.u_offset[1]) == ip->i_size1)
{ rp->f_offset[1] = 0;
ip->i_size1 = 0;
/* BBN: mek ( 4/30/79 ) - free the current buffer page */
bdfree(ip, curpage);
if (ip->i_mode&IWRITE) {
ip->i_mode =& ~IWRITE;
wakeup(ip+1);
}
}
/* avoid awake if called from portread */
if ( flag != -1 )
awakei(ip,-1); /* bbn:mek---awake other end */
prele(ip);
}
/*
* 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;
}
/*
* rand:bobg--if there is a pending eof, sleep till it is read
*/
while (ip->i_flag & IEOFP) /* any other eofs pending? */
{
prele(ip);
sleep(ip+3,PPIPE); /* sleep till a reader reads an eof */
plock(ip);
}
/*
* If the pipe is full,
* wait for reads to deplete
* and truncate it.
*/
if(ip->i_size1 == PIPSIZ) {
ip->i_mode =| IWRITE;
prele(ip);
sleep(ip+1, PPIPE);
goto loop;
}
/*
* Write what is possible and
* loop back.
*/
u.u_offset[0] = 0;
u.u_offset[1] = ip->i_size1;
u.u_count = min(c, PIPSIZ-u.u_offset[1]);
c =- u.u_count;
writei(ip);
awakei(ip,-1); /* bbn:mek---awake other end */
prele(ip);
if(ip->i_mode&IREAD) {
ip->i_mode =& ~IREAD;
wakeup(ip+2);
}
goto loop;
}
/*
* eofp routine (rand:bobg) to write a single eof on a pipe
* passed a ptr to an inode by eofp/sys1 code
*/
eofp(pin)
{
register int *ip;
plock(ip = pin);
if(ip->i_count < 2) /* make sure someone will read EOF */
{
prele(ip); /* other end must have died */
u.u_error = EPIPE;
psignal(u.u_procp, SIGPIPE); /* let writer know */
return;
}
while (ip->i_flag & IEOFP) /* any other eofs pending? */
{ /* sleep till last EOF handled */
prele(ip);
sleep(ip+3,PPIPE); /* sleep till a reader reads an eof */
plock(ip);
}
ip->i_flag =| IEOFP; /* announce EOF to next read */
prele(ip);
if (ip->i_mode & IREAD) /* wakeup any waiting reads */
{
ip->i_mode =& ~IREAD;
wakeup(ip+2);
}
}
/*
* Lock a pipe.
* If its already locked,
* set the WANT bit and sleep.
*/
plock(ip)
int *ip;
{
register *rp;
rp = ip;
while(rp->i_flag&ILOCK) {
rp->i_flag =| IWANT;
sleep(rp, PPIPE);
}
rp->i_flag =| ILOCK;
}
/*
* Unlock a pipe.
* If WANT bit is on,
* wakeup.
* This routine is also used
* to unlock inodes in general.
*/
prele(ip)
int *ip;
{
register *rp;
rp = ip;
rp->i_flag =& ~ILOCK;
if(rp->i_flag&IWANT) {
rp->i_flag =& ~IWANT;
wakeup(rp);
}
}