diff options
author | dzwdz | 2022-07-06 19:46:35 +0200 |
---|---|---|
committer | dzwdz | 2022-07-06 19:46:35 +0200 |
commit | caec20e9886fd6d0437b59a9de48a7b686a2cc09 (patch) | |
tree | 2b2e06d90876168a81fdcda15029cd1a2eaffd0a /src | |
parent | a89984d7200381d7b8035c48124d93105d59cf24 (diff) |
kernel/pipes: read & write support
Diffstat (limited to 'src')
-rw-r--r-- | src/init/tests/main.c | 32 | ||||
-rw-r--r-- | src/init/tests/main.h | 12 | ||||
-rw-r--r-- | src/init/tests/pipe.c | 41 | ||||
-rw-r--r-- | src/kernel/handle.h | 3 | ||||
-rw-r--r-- | src/kernel/pipe.c | 43 | ||||
-rw-r--r-- | src/kernel/pipe.h | 7 | ||||
-rw-r--r-- | src/kernel/syscalls.c | 43 |
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); } |