summaryrefslogtreecommitdiff
path: root/src/kernel
diff options
context:
space:
mode:
authordzwdz2022-07-06 19:46:35 +0200
committerdzwdz2022-07-06 19:46:35 +0200
commitcaec20e9886fd6d0437b59a9de48a7b686a2cc09 (patch)
tree2b2e06d90876168a81fdcda15029cd1a2eaffd0a /src/kernel
parenta89984d7200381d7b8035c48124d93105d59cf24 (diff)
kernel/pipes: read & write support
Diffstat (limited to 'src/kernel')
-rw-r--r--src/kernel/handle.h3
-rw-r--r--src/kernel/pipe.c43
-rw-r--r--src/kernel/pipe.h7
-rw-r--r--src/kernel/syscalls.c43
4 files changed, 59 insertions, 37 deletions
diff --git a/src/kernel/handle.h b/src/kernel/handle.h
index d644521..423ea88 100644
--- a/src/kernel/handle.h
+++ b/src/kernel/handle.h
@@ -18,8 +18,7 @@ struct handle {
struct vfs_backend *backend; // HANDLE_FILE | HANDLE_FS_FRONT
int file_id; // only applicable to HANDLE_FILE
struct {
- struct process *stuck;
- bool wants_write; // refers to the waiting process
+ struct process *reader, *writer;
} pipe;
size_t refcount;
diff --git a/src/kernel/pipe.c b/src/kernel/pipe.c
new file mode 100644
index 0000000..8afd359
--- /dev/null
+++ b/src/kernel/pipe.c
@@ -0,0 +1,43 @@
+#include <kernel/mem/virt.h>
+#include <kernel/panic.h>
+#include <kernel/pipe.h>
+#include <kernel/util.h>
+
+void pipe_joinqueue(struct handle *h, bool wants_write,
+ struct process *proc, void __user *pbuf, size_t pbuflen)
+{
+ struct process **slot = wants_write ? &h->pipe.reader : &h->pipe.writer;
+ if (*slot) {
+ assert((*slot)->state == PS_WAITS4PIPE);
+ panic_unimplemented();
+ }
+
+ process_transition(proc, PS_WAITS4PIPE);
+ *slot = proc;
+ proc->waits4pipe.pipe = h;
+ proc->waits4pipe.buf = pbuf;
+ proc->waits4pipe.len = pbuflen;
+}
+
+void pipe_trytransfer(struct handle *h) {
+ struct process *rdr = h->pipe.reader, *wtr = h->pipe.writer;
+ int len;
+ if (!(rdr && wtr)) return;
+ assert(rdr->state == PS_WAITS4PIPE);
+ assert(wtr->state == PS_WAITS4PIPE);
+
+ len = min(rdr->waits4pipe.len, wtr->waits4pipe.len);
+
+ if (!virt_cpy(
+ rdr->pages, rdr->waits4pipe.buf,
+ wtr->pages, wtr->waits4pipe.buf, len))
+ {
+ panic_unimplemented();
+ }
+ process_transition(rdr, PS_RUNNING);
+ process_transition(wtr, PS_RUNNING);
+ h->pipe.reader = NULL;
+ h->pipe.writer = NULL;
+ regs_savereturn(&rdr->regs, len);
+ regs_savereturn(&wtr->regs, len);
+}
diff --git a/src/kernel/pipe.h b/src/kernel/pipe.h
new file mode 100644
index 0000000..facaaaa
--- /dev/null
+++ b/src/kernel/pipe.h
@@ -0,0 +1,7 @@
+#pragma once
+#include <kernel/proc.h>
+
+void pipe_joinqueue(struct handle *h, bool wants_write,
+ struct process *proc, void __user *pbuf, size_t pbuflen);
+
+void pipe_trytransfer(struct handle *h);
diff --git a/src/kernel/syscalls.c b/src/kernel/syscalls.c
index 4a59811..05616a3 100644
--- a/src/kernel/syscalls.c
+++ b/src/kernel/syscalls.c
@@ -2,6 +2,7 @@
#include <kernel/mem/alloc.h>
#include <kernel/mem/virt.h>
#include <kernel/panic.h>
+#include <kernel/pipe.h>
#include <kernel/proc.h>
#include <kernel/vfs/path.h>
#include <shared/flags.h>
@@ -28,7 +29,7 @@ int _syscall_await(void) {
{
if (iter->noreap) continue;
has_children = true;
- if (iter->state == PS_DEAD)
+ if (iter->state == PS_DEAD) // TODO this path crashes
SYSCALL_RETURN(process_try2collect(iter));
}
@@ -188,20 +189,8 @@ int _syscall_read(handle_t handle_num, void __user *buf, size_t len, int offset)
.backend = h->backend,
});
} else if ((h = process_handle_get(process_current, handle_num, HANDLE_PIPE))) {
- if (h->pipe.stuck && h->pipe.wants_write)
- panic_unimplemented(); // TODO pipe queue
-
- if (h->pipe.stuck) {
- assert(h->pipe.stuck->state == PS_WAITS4PIPE);
- panic_unimplemented();
- } else {
- process_transition(process_current, PS_WAITS4PIPE);
- h->pipe.stuck = process_current;
- h->pipe.wants_write = true;
- process_current->waits4pipe.pipe = h;
- process_current->waits4pipe.buf = buf;
- process_current->waits4pipe.len = len;
- }
+ pipe_joinqueue(h, true, process_current, buf, len);
+ pipe_trytransfer(h);
} else {
SYSCALL_RETURN(-1);
}
@@ -223,25 +212,8 @@ int _syscall_write(handle_t handle_num, const void __user *buf, size_t len, int
.backend = h->backend,
});
} else if ((h = process_handle_get(process_current, handle_num, HANDLE_PIPE))) {
- if (h->pipe.stuck && !h->pipe.wants_write)
- panic_unimplemented(); // TODO pipe queue
-
- if (h->pipe.stuck) {
- struct process *p = h->pipe.stuck;
- assert(p->state == PS_WAITS4PIPE);
- if (len <= p->waits4pipe.len) {
- bool succ = virt_cpy(
- p->pages, p->waits4pipe.buf,
- process_current->pages, buf, len);
- if (!succ) panic_unimplemented();
- process_transition(p, PS_RUNNING);
- regs_savereturn(&p->regs, len);
-
- SYSCALL_RETURN(len);
- } else panic_unimplemented();
- } else {
- panic_unimplemented();
- }
+ pipe_joinqueue(h, false, process_current, (void __user *)buf, len);
+ pipe_trytransfer(h);
} else {
SYSCALL_RETURN(-1);
}
@@ -337,7 +309,8 @@ handle_t _syscall_pipe(int flags) {
handle_t h = process_find_free_handle(process_current, 0);
if (h < 0) return -1;
process_current->handles[h] = handle_init(HANDLE_PIPE);
- assert(process_current->handles[h]->pipe.stuck == NULL);
+ assert(process_current->handles[h]->pipe.reader == NULL);
+ assert(process_current->handles[h]->pipe.writer == NULL);
SYSCALL_RETURN(h);
}