summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/init/tests/main.c32
-rw-r--r--src/init/tests/main.h12
-rw-r--r--src/init/tests/pipe.c41
-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
7 files changed, 113 insertions, 68 deletions
diff --git a/src/init/tests/main.c b/src/init/tests/main.c
index e5e3941..c59b390 100644
--- a/src/init/tests/main.c
+++ b/src/init/tests/main.c
@@ -1,17 +1,9 @@
+#define TEST_MACROS
#include <init/stdlib.h>
#include <init/tests/main.h>
#include <shared/flags.h>
#include <shared/syscalls.h>
-#define argify(str) str, sizeof(str) - 1
-
-#define test_fail() do { \
- printf("\033[31m" "TEST FAILED: %s:%xh\n" "\033[0m", __func__, __LINE__); \
- return; \
-} while (0)
-
-#define assert(cond) if (!(cond)) test_fail();
-
static void run_forked(void (*fn)()) {
if (!_syscall_fork(0, NULL)) {
fn();
@@ -141,28 +133,6 @@ static void test_malloc(void) {
free(p1);
}
-static void test_pipe(void) {
- const char *msgs[2] = {"hello", "world"};
- char buf[16];
- int ret;
- handle_t pipe = _syscall_pipe(0);
- assert(pipe > 0);
-
- if (!_syscall_fork(0, NULL)) {
- ret = _syscall_write(pipe, msgs[0], 5, -1);
- assert(ret == 5);
- _syscall_exit(0);
- } else {
- ret = _syscall_read(pipe, buf, 16, 0);
- assert(ret == 5);
- assert(!memcmp(buf, msgs[0], 5));
- }
-
- // TODO vice versa
- // TODO partial reads, writes
- // TODO kill process that's waiting on a pipe
-}
-
static void stress_fork(void) {
/* run a lot of processes */
for (size_t i = 0; i < 2048; i++) {
diff --git a/src/init/tests/main.h b/src/init/tests/main.h
index 9a2afd2..97678e3 100644
--- a/src/init/tests/main.h
+++ b/src/init/tests/main.h
@@ -1,3 +1,15 @@
#pragma once
void test_all(void);
+void test_pipe(void);
+
+#ifdef TEST_MACROS
+
+#define argify(str) str, sizeof(str) - 1
+#define test_fail() do { \
+ printf("\033[31m" "TEST FAILED: %s:%xh\n" "\033[0m", __func__, __LINE__); \
+ return; \
+} while (0)
+#define assert(cond) if (!(cond)) test_fail();
+
+#endif
diff --git a/src/init/tests/pipe.c b/src/init/tests/pipe.c
new file mode 100644
index 0000000..bbfe79a
--- /dev/null
+++ b/src/init/tests/pipe.c
@@ -0,0 +1,41 @@
+#define TEST_MACROS
+#include <init/stdlib.h>
+#include <init/tests/main.h>
+#include <shared/flags.h>
+#include <shared/syscalls.h>
+
+static const char *pipe_msgs[2] = {"hello", "world"};
+
+static void test_pipe_child(handle_t pipe) {
+ int ret = _syscall_write(pipe, pipe_msgs[0], 5, -1);
+ assert(ret == 5);
+
+ ret = _syscall_write(pipe, pipe_msgs[1], 5, -1);
+ assert(ret == 5);
+}
+
+static void test_pipe_parent(handle_t pipe) {
+ char buf[16];
+ int ret = _syscall_read(pipe, buf, 16, 0);
+ assert(ret == 5);
+ assert(!memcmp(buf, pipe_msgs[0], 5));
+
+ _syscall_read(pipe, buf, 16, 0);
+ assert(ret == 5);
+ assert(!memcmp(buf, pipe_msgs[1], 5)); // wrong compare for test
+}
+
+void test_pipe(void) {
+ handle_t pipe = _syscall_pipe(0);
+ assert(pipe > 0);
+
+ if (!_syscall_fork(0, NULL)) {
+ test_pipe_child(pipe);
+ _syscall_exit(0);
+ } else {
+ test_pipe_parent(pipe);
+ _syscall_await();
+ }
+
+ // TODO kill process that's waiting on a pipe
+}
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);
}