123 lines
2.8 KiB
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;
|
||
|
}
|