summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordzwdz2022-07-05 22:51:21 +0200
committerdzwdz2022-07-05 22:51:21 +0200
commita89984d7200381d7b8035c48124d93105d59cf24 (patch)
tree01e788518dca3c5cdb269e82b6a272612ab51970
parentb16ab3edc8d3f3d5bcbe0afc8dec3e9ed822a224 (diff)
kernel: initial partial pipe support
-rw-r--r--src/init/syscalls.c4
-rw-r--r--src/init/tests/main.c23
-rw-r--r--src/kernel/handle.c5
-rw-r--r--src/kernel/handle.h8
-rw-r--r--src/kernel/proc.c1
-rw-r--r--src/kernel/proc.h6
-rw-r--r--src/kernel/syscalls.c107
-rw-r--r--src/shared/syscalls.h2
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);