diff options
author | dzwdz | 2022-07-05 22:51:21 +0200 |
---|---|---|
committer | dzwdz | 2022-07-05 22:51:21 +0200 |
commit | a89984d7200381d7b8035c48124d93105d59cf24 (patch) | |
tree | 01e788518dca3c5cdb269e82b6a272612ab51970 | |
parent | b16ab3edc8d3f3d5bcbe0afc8dec3e9ed822a224 (diff) |
kernel: initial partial pipe support
-rw-r--r-- | src/init/syscalls.c | 4 | ||||
-rw-r--r-- | src/init/tests/main.c | 23 | ||||
-rw-r--r-- | src/kernel/handle.c | 5 | ||||
-rw-r--r-- | src/kernel/handle.h | 8 | ||||
-rw-r--r-- | src/kernel/proc.c | 1 | ||||
-rw-r--r-- | src/kernel/proc.h | 6 | ||||
-rw-r--r-- | src/kernel/syscalls.c | 107 | ||||
-rw-r--r-- | src/shared/syscalls.h | 2 |
8 files changed, 127 insertions, 29 deletions
diff --git a/src/init/syscalls.c b/src/init/syscalls.c index 6e4c2dc..54ea715 100644 --- a/src/init/syscalls.c +++ b/src/init/syscalls.c @@ -50,6 +50,10 @@ void __user *_syscall_memflag(void __user *addr, size_t len, int flags) { return (void __user *)_syscall(_SYSCALL_MEMFLAG, (int)addr, (int)len, flags, 0); } +handle_t _syscall_pipe(int flags) { + return (handle_t)_syscall(_SYSCALL_PIPE, flags, 0, 0, 0); +} + void _syscall_debug_klog(const void __user *buf, size_t len) { return (void)_syscall(_SYSCALL_DEBUG_KLOG, (int)buf, (int)len, 0, 0); } diff --git a/src/init/tests/main.c b/src/init/tests/main.c index 1260a35..e5e3941 100644 --- a/src/init/tests/main.c +++ b/src/init/tests/main.c @@ -141,6 +141,28 @@ 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++) { @@ -157,5 +179,6 @@ void test_all(void) { run_forked(test_orphaned_fs); run_forked(test_memflag); run_forked(test_malloc); + run_forked(test_pipe); run_forked(stress_fork); } diff --git a/src/kernel/handle.c b/src/kernel/handle.c index ac8db1f..70830ff 100644 --- a/src/kernel/handle.c +++ b/src/kernel/handle.c @@ -3,9 +3,11 @@ #include <kernel/panic.h> #include <kernel/proc.h> #include <kernel/vfs/request.h> +#include <shared/mem.h> struct handle *handle_init(enum handle_type type) { struct handle *h = kmalloc(sizeof *h); + memset(h, 0, sizeof *h); h->type = type; h->refcount = 1; return h; @@ -25,7 +27,8 @@ void handle_close(struct handle *h) { }); } - vfs_backend_refdown(h->backend); + if (h->backend) + vfs_backend_refdown(h->backend); // TODO sanity check to check if refcount is true. handle_sanity? diff --git a/src/kernel/handle.h b/src/kernel/handle.h index 088ff93..d644521 100644 --- a/src/kernel/handle.h +++ b/src/kernel/handle.h @@ -9,14 +9,18 @@ enum handle_type; // forward declaration for proc.h enum handle_type { HANDLE_INVALID = 0, HANDLE_FILE, - + HANDLE_PIPE, HANDLE_FS_FRONT, }; struct handle { enum handle_type type; - struct vfs_backend *backend; + 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 + } pipe; size_t refcount; }; diff --git a/src/kernel/proc.c b/src/kernel/proc.c index 90e24f7..717af11 100644 --- a/src/kernel/proc.c +++ b/src/kernel/proc.c @@ -263,6 +263,7 @@ void process_transition(struct process *p, enum process_state state) { case PS_WAITS4CHILDDEATH: case PS_WAITS4FS: case PS_WAITS4REQUEST: + case PS_WAITS4PIPE: assert(last == PS_RUNNING); break; diff --git a/src/kernel/proc.h b/src/kernel/proc.h index 93044d2..eb5bd6b 100644 --- a/src/kernel/proc.h +++ b/src/kernel/proc.h @@ -14,6 +14,7 @@ enum process_state { PS_WAITS4CHILDDEATH, PS_WAITS4FS, PS_WAITS4REQUEST, + PS_WAITS4PIPE, PS_LAST, }; @@ -42,6 +43,11 @@ struct process { size_t max_len; struct fs_wait_response __user *res; } awaited_req; // PS_WAITS4REQUEST + struct { + struct handle *pipe; + char __user *buf; + size_t len; + } waits4pipe; }; struct vfs_request *handled_req; diff --git a/src/kernel/syscalls.c b/src/kernel/syscalls.c index efa1d54..4a59811 100644 --- a/src/kernel/syscalls.c +++ b/src/kernel/syscalls.c @@ -173,36 +173,78 @@ fail: } int _syscall_read(handle_t handle_num, void __user *buf, size_t len, int offset) { - struct handle *handle = process_handle_get(process_current, handle_num, HANDLE_FILE); - if (!handle) SYSCALL_RETURN(-1); - vfsreq_create((struct vfs_request) { - .type = VFSOP_READ, - .output = { - .buf = (userptr_t) buf, - .len = len, - }, - .id = handle->file_id, - .offset = offset, - .caller = process_current, - .backend = handle->backend, - }); + struct handle *h; + // TODO get rid of the type argument in process_handle_get + if ((h = process_handle_get(process_current, handle_num, HANDLE_FILE))) { + vfsreq_create((struct vfs_request) { + .type = VFSOP_READ, + .output = { + .buf = (userptr_t) buf, + .len = len, + }, + .id = h->file_id, + .offset = offset, + .caller = process_current, + .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; + } + } else { + SYSCALL_RETURN(-1); + } return -1; // dummy } int _syscall_write(handle_t handle_num, const void __user *buf, size_t len, int offset) { - struct handle *handle = process_handle_get(process_current, handle_num, HANDLE_FILE); - if (!handle) SYSCALL_RETURN(-1); - vfsreq_create((struct vfs_request) { - .type = VFSOP_WRITE, - .input = { - .buf = (userptr_t) buf, - .len = len, - }, - .id = handle->file_id, - .offset = offset, - .caller = process_current, - .backend = handle->backend, - }); + struct handle *h; + if ((h = process_handle_get(process_current, handle_num, HANDLE_FILE))) { + vfsreq_create((struct vfs_request) { + .type = VFSOP_WRITE, + .input = { + .buf = (userptr_t) buf, + .len = len, + }, + .id = h->file_id, + .offset = offset, + .caller = process_current, + .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(); + } + } else { + SYSCALL_RETURN(-1); + } return -1; // dummy } @@ -289,6 +331,16 @@ ret: // the macro is too stupid to handle returning pointers return addr; } +handle_t _syscall_pipe(int flags) { + if (flags) return -1; + + 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); + SYSCALL_RETURN(h); +} + void _syscall_debug_klog(const void __user *buf, size_t len) { (void)buf; (void)len; // static char kbuf[256]; @@ -333,6 +385,9 @@ int _syscall(int num, int a, int b, int c, int d) { case _SYSCALL_MEMFLAG: _syscall_memflag((userptr_t)a, b, c); break; + case _SYSCALL_PIPE: + _syscall_pipe(a); + break; case _SYSCALL_DEBUG_KLOG: _syscall_debug_klog((userptr_t)a, b); break; diff --git a/src/shared/syscalls.h b/src/shared/syscalls.h index 9587e78..31f6d73 100644 --- a/src/shared/syscalls.h +++ b/src/shared/syscalls.h @@ -24,6 +24,7 @@ enum { _SYSCALL_FS_RESPOND, _SYSCALL_MEMFLAG, + _SYSCALL_PIPE, _SYSCALL_DEBUG_KLOG, }; @@ -80,5 +81,6 @@ int _syscall_fs_respond(char __user *buf, int ret); * @return address of the first affected page (usually == addr) */ void __user *_syscall_memflag(void __user *addr, size_t len, int flags); +handle_t _syscall_pipe(int flags); void _syscall_debug_klog(const void __user *buf, size_t len); |