223 lines
3.1 KiB
C
223 lines
3.1 KiB
C
#
|
|
/*
|
|
*/
|
|
|
|
#include "../param.h"
|
|
#include "../systm.h"
|
|
#include "../user.h"
|
|
#include "../inode.h"
|
|
#include "../file.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;
|
|
ip->i_mode = IALLOC;
|
|
}
|
|
|
|
/*
|
|
* 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 the head (read) has caught up with
|
|
* the tail (write), reset both to 0.
|
|
*/
|
|
|
|
if(rp->f_offset[1] == ip->i_size1) {
|
|
if(rp->f_offset[1] != 0) {
|
|
rp->f_offset[1] = 0;
|
|
ip->i_size1 = 0;
|
|
if(ip->i_mode&IWRITE) {
|
|
ip->i_mode =& ~IWRITE;
|
|
wakeup(ip+1);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 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);
|
|
rp->f_offset[1] = u.u_offset[1];
|
|
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;
|
|
}
|
|
|
|
/*
|
|
* 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);
|
|
prele(ip);
|
|
if(ip->i_mode&IREAD) {
|
|
ip->i_mode =& ~IREAD;
|
|
wakeup(ip+2);
|
|
}
|
|
goto loop;
|
|
}
|
|
|
|
/*
|
|
* 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);
|
|
}
|
|
}
|