summaryrefslogtreecommitdiff
path: root/kernel/pipe.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/pipe.c')
-rw-r--r--kernel/pipe.c127
1 files changed, 127 insertions, 0 deletions
diff --git a/kernel/pipe.c b/kernel/pipe.c
new file mode 100644
index 0000000..e358283
--- /dev/null
+++ b/kernel/pipe.c
@@ -0,0 +1,127 @@
+#include "types.h"
+#include "riscv.h"
+#include "defs.h"
+#include "param.h"
+#include "spinlock.h"
+#include "proc.h"
+#include "fs.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
+};
+
+int
+pipealloc(struct file **f0, struct file **f1)
+{
+ struct pipe *pi;
+
+ pi = 0;
+ *f0 = *f1 = 0;
+ if((*f0 = filealloc()) == 0 || (*f1 = filealloc()) == 0)
+ goto bad;
+ if((pi = (struct pipe*)kalloc()) == 0)
+ goto bad;
+ pi->readopen = 1;
+ pi->writeopen = 1;
+ pi->nwrite = 0;
+ pi->nread = 0;
+ initlock(&pi->lock, "pipe");
+ (*f0)->type = FD_PIPE;
+ (*f0)->readable = 1;
+ (*f0)->writable = 0;
+ (*f0)->pipe = pi;
+ (*f1)->type = FD_PIPE;
+ (*f1)->readable = 0;
+ (*f1)->writable = 1;
+ (*f1)->pipe = pi;
+ return 0;
+
+ bad:
+ if(pi)
+ kfree((char*)pi);
+ if(*f0)
+ fileclose(*f0);
+ if(*f1)
+ fileclose(*f1);
+ return -1;
+}
+
+void
+pipeclose(struct pipe *pi, int writable)
+{
+ acquire(&pi->lock);
+ if(writable){
+ pi->writeopen = 0;
+ wakeup(&pi->nread);
+ } else {
+ pi->readopen = 0;
+ wakeup(&pi->nwrite);
+ }
+ if(pi->readopen == 0 && pi->writeopen == 0){
+ release(&pi->lock);
+ kfree((char*)pi);
+ } else
+ release(&pi->lock);
+}
+
+int
+pipewrite(struct pipe *pi, uint64 addr, int n)
+{
+ int i;
+ char ch;
+ struct proc *pr = myproc();
+
+ acquire(&pi->lock);
+ for(i = 0; i < n; i++){
+ while(pi->nwrite == pi->nread + PIPESIZE){ //DOC: pipewrite-full
+ if(pi->readopen == 0 || myproc()->killed){
+ release(&pi->lock);
+ return -1;
+ }
+ wakeup(&pi->nread);
+ sleep(&pi->nwrite, &pi->lock);
+ }
+ if(copyin(pr->pagetable, &ch, addr + i, 1) == -1)
+ break;
+ pi->data[pi->nwrite++ % PIPESIZE] = ch;
+ }
+ wakeup(&pi->nread);
+ release(&pi->lock);
+ return n;
+}
+
+int
+piperead(struct pipe *pi, uint64 addr, int n)
+{
+ int i;
+ struct proc *pr = myproc();
+ char ch;
+
+ acquire(&pi->lock);
+ while(pi->nread == pi->nwrite && pi->writeopen){ //DOC: pipe-empty
+ if(myproc()->killed){
+ release(&pi->lock);
+ return -1;
+ }
+ sleep(&pi->nread, &pi->lock); //DOC: piperead-sleep
+ }
+ for(i = 0; i < n; i++){ //DOC: piperead-copy
+ if(pi->nread == pi->nwrite)
+ break;
+ ch = pi->data[pi->nread++ % PIPESIZE];
+ if(copyout(pr->pagetable, addr + i, &ch, 1) == -1)
+ break;
+ }
+ wakeup(&pi->nwrite); //DOC: piperead-wakeup
+ release(&pi->lock);
+ return i;
+}