xv6/pipe.c

123 lines
2.8 KiB
C

#include "types.h"
#include "defs.h"
#include "param.h"
#include "mmu.h"
#include "proc.h"
#include "fs.h"
#include "spinlock.h"
#include "sleeplock.h"
#include "file.h"
#define PIPESIZE 512
struct pipe {
struct spinlock lock;
char data[PIPESIZE];
uint nread; // number of bytes read
uint nwrite; // number of bytes written
int readopen; // read fd is still open
int writeopen; // write fd is still open
};
void cleanuppipealloc(struct pipe *p, struct file **f0, struct file **f1) {
if (p) {
kfree((char*)p);
}
if (*f0) {
fileclose(*f0);
}
if (*f1) {
fileclose(*f1);
}
}
int pipealloc(struct file **f0, struct file **f1) {
struct pipe *p;
p = 0;
*f0 = *f1 = 0;
if ((*f0 = filealloc()) == 0 || (*f1 = filealloc()) == 0) {
cleanuppipealloc(p, f0, f1);
return -1;
}
if ((p = (struct pipe*)kalloc()) == 0) {
cleanuppipealloc(p, f0, f1);
return -1;
}
p->readopen = 1;
p->writeopen = 1;
p->nwrite = 0;
p->nread = 0;
initlock(&p->lock, "pipe");
(*f0)->type = FD_PIPE;
(*f0)->readable = 1;
(*f0)->writable = 0;
(*f0)->pipe = p;
(*f1)->type = FD_PIPE;
(*f1)->readable = 0;
(*f1)->writable = 1;
(*f1)->pipe = p;
return 0;
}
void pipeclose(struct pipe *p, int writable) {
acquire(&p->lock);
if (writable) {
p->writeopen = 0;
wakeup(&p->nread);
}
else {
p->readopen = 0;
wakeup(&p->nwrite);
}
if (p->readopen == 0 && p->writeopen == 0) {
release(&p->lock);
kfree((char*)p);
}
else {
release(&p->lock);
}
}
int pipewrite(struct pipe *p, char *addr, int n) {
int i;
acquire(&p->lock);
for (i = 0; i < n; i++) {
while (p->nwrite == p->nread + PIPESIZE) { //DOC: pipewrite-full
if (p->readopen == 0 || myproc()->killed) {
release(&p->lock);
return -1;
}
wakeup(&p->nread);
sleep(&p->nwrite, &p->lock); //DOC: pipewrite-sleep
}
p->data[p->nwrite++ % PIPESIZE] = addr[i];
}
wakeup(&p->nread); //DOC: pipewrite-wakeup1
release(&p->lock);
return n;
}
int piperead(struct pipe *p, char *addr, int n) {
int i;
acquire(&p->lock);
while (p->nread == p->nwrite && p->writeopen) { //DOC: pipe-empty
if (myproc()->killed) {
release(&p->lock);
return -1;
}
sleep(&p->nread, &p->lock); //DOC: piperead-sleep
}
for (i = 0; i < n; i++) { //DOC: piperead-copy
if (p->nread == p->nwrite) {
break;
}
addr[i] = p->data[p->nread++ % PIPESIZE];
}
wakeup(&p->nwrite); //DOC: piperead-wakeup
release(&p->lock);
return i;
}