xv6/pipe.c
rtm 46bbd72f3e no more recursive locks
wakeup1() assumes you hold proc_table_lock
sleep(chan, lock) provides atomic sleep-and-release to wait for condition
ugly code in swtch/scheduler to implement new sleep
fix lots of bugs in pipes, wait, and exit
fix bugs if timer interrupt goes off in schedule()
console locks per line, not per byte
2006-07-15 12:03:57 +00:00

125 lines
2.2 KiB
C

#include "types.h"
#include "param.h"
#include "x86.h"
#include "mmu.h"
#include "proc.h"
#include "defs.h"
#include "fd.h"
#include "spinlock.h"
#define PIPESIZE 512
struct pipe {
int readopen; // read fd is still open
int writeopen; // write fd is still open
int writep; // next index to write
int readp; // next index to read
struct spinlock lock;
char data[PIPESIZE];
};
int
pipe_alloc(struct fd **fd1, struct fd **fd2)
{
*fd1 = *fd2 = 0;
struct pipe *p = 0;
if((*fd1 = fd_alloc()) == 0)
goto oops;
if((*fd2 = fd_alloc()) == 0)
goto oops;
if((p = (struct pipe *) kalloc(PAGE)) == 0)
goto oops;
p->readopen = 1;
p->writeopen = 1;
p->writep = 0;
p->readp = 0;
memset(&p->lock, 0, sizeof(p->lock));
(*fd1)->type = FD_PIPE;
(*fd1)->readable = 1;
(*fd1)->writeable = 0;
(*fd1)->pipe = p;
(*fd2)->type = FD_PIPE;
(*fd2)->readable = 0;
(*fd2)->writeable = 1;
(*fd2)->pipe = p;
return 0;
oops:
if(p)
kfree((char *) p, PAGE);
if(*fd1){
(*fd1)->type = FD_NONE;
fd_close(*fd1);
}
if(*fd2){
(*fd2)->type = FD_NONE;
fd_close(*fd2);
}
return -1;
}
void
pipe_close(struct pipe *p, int writeable)
{
if(writeable){
p->writeopen = 0;
wakeup(&p->readp);
} else {
p->readopen = 0;
wakeup(&p->writep);
}
if(p->readopen == 0 && p->writeopen == 0)
kfree((char *) p, PAGE);
}
int
pipe_write(struct pipe *p, char *addr, int n)
{
int i;
acquire(&p->lock);
for(i = 0; i < n; i++){
while(((p->writep + 1) % PIPESIZE) == p->readp){
if(p->readopen == 0){
release(&p->lock);
return -1;
}
wakeup(&p->readp);
sleep(&p->writep, &p->lock);
}
p->data[p->writep] = addr[i];
p->writep = (p->writep + 1) % PIPESIZE;
}
release(&p->lock);
wakeup(&p->readp);
return i;
}
int
pipe_read(struct pipe *p, char *addr, int n)
{
int i;
acquire(&p->lock);
while(p->readp == p->writep){
if(p->writeopen == 0){
release(&p->lock);
return 0;
}
sleep(&p->readp, &p->lock);
}
for(i = 0; i < n; i++){
if(p->readp == p->writep)
break;
addr[i] = p->data[p->readp];
p->readp = (p->readp + 1) % PIPESIZE;
}
release(&p->lock);
wakeup(&p->writep);
return i;
}