diff options
-rw-r--r-- | src/kernel/proc.c | 23 | ||||
-rw-r--r-- | src/kernel/proc.h | 3 | ||||
-rw-r--r-- | src/shared/include/camellia/flags.h | 1 | ||||
-rw-r--r-- | src/user/app/tests/kernel/threads.c | 24 | ||||
-rw-r--r-- | src/user/app/tests/tests.c | 1 | ||||
-rw-r--r-- | src/user/app/tests/tests.h | 1 | ||||
-rw-r--r-- | src/user/lib/thread.S | 8 | ||||
-rw-r--r-- | src/user/lib/thread.c | 11 | ||||
-rw-r--r-- | src/user/lib/thread.h | 4 |
9 files changed, 74 insertions, 2 deletions
diff --git a/src/kernel/proc.c b/src/kernel/proc.c index 2e765c7..906fc29 100644 --- a/src/kernel/proc.c +++ b/src/kernel/proc.c @@ -50,7 +50,17 @@ struct process *process_fork(struct process *parent, int flags) { struct process *child = kmalloc(sizeof *child); memset(child, 0, sizeof *child); - child->pages = pagedir_copy(parent->pages); + if (flags & FORK_SHAREMEM) { + if (!parent->pages_refcount) { + parent->pages_refcount = kmalloc(sizeof *parent->pages_refcount); + *parent->pages_refcount = 1; + } + *parent->pages_refcount += 1; + child->pages_refcount = parent->pages_refcount; + child->pages = parent->pages; + } else { + child->pages = pagedir_copy(parent->pages); + } child->regs = parent->regs; child->state = parent->state; assert(child->state == PS_RUNNING); // not copying the state union @@ -152,7 +162,16 @@ void process_kill(struct process *p, int ret) { p->execbuf.buf = NULL; } - pagedir_free(p->pages); + if (p->pages_refcount) { + assert(*p->pages_refcount != 0); + *p->pages_refcount -= 1; + if (*p->pages_refcount == 0) { + kfree(p->pages_refcount); + pagedir_free(p->pages); + } + } else { + pagedir_free(p->pages); + } // TODO VULN unbounded recursion struct process *c2; diff --git a/src/kernel/proc.h b/src/kernel/proc.h index 27327c4..e7946b2 100644 --- a/src/kernel/proc.h +++ b/src/kernel/proc.h @@ -20,6 +20,9 @@ enum process_state { struct process { struct pagedir *pages; + /* if NULL, refcount == 1. kmalloc'd */ + uint64_t *pages_refcount; + struct registers regs; struct process *sibling, *child, *parent; diff --git a/src/shared/include/camellia/flags.h b/src/shared/include/camellia/flags.h index 5b8f834..30762bd 100644 --- a/src/shared/include/camellia/flags.h +++ b/src/shared/include/camellia/flags.h @@ -5,6 +5,7 @@ #define FORK_NOREAP 1 #define FORK_NEWFS 2 +#define FORK_SHAREMEM 4 #define WRITE_TRUNCATE 1 diff --git a/src/user/app/tests/kernel/threads.c b/src/user/app/tests/kernel/threads.c new file mode 100644 index 0000000..9f08c39 --- /dev/null +++ b/src/user/app/tests/kernel/threads.c @@ -0,0 +1,24 @@ +#include "../tests.h" +#include <camellia/flags.h> +#include <camellia/syscalls.h> +#include <user/lib/esemaphore.h> +#include <user/lib/thread.h> + +int global_n; + +static void basic_thread(void *sem) { + global_n = 10; + esem_signal(sem); +} + +static void test_basic_thread(void) { + struct evil_sem *sem = esem_new(0); + global_n = 0; + thread_create(FORK_NOREAP, basic_thread, sem); + esem_wait(sem); + test(global_n == 10); +} + +void r_k_threads(void) { + run_test(test_basic_thread); +} diff --git a/src/user/app/tests/tests.c b/src/user/app/tests/tests.c index 2157e60..f9b085a 100644 --- a/src/user/app/tests/tests.c +++ b/src/user/app/tests/tests.c @@ -17,6 +17,7 @@ int main(void) { r_k_misc(); r_k_miscsyscall(); r_k_path(); + r_k_threads(); r_libc_esemaphore(); r_libc_string(); r_s_printf(); diff --git a/src/user/app/tests/tests.h b/src/user/app/tests/tests.h index 79169c9..d092115 100644 --- a/src/user/app/tests/tests.h +++ b/src/user/app/tests/tests.h @@ -11,6 +11,7 @@ void r_k_fs(void); void r_k_misc(void); void r_k_miscsyscall(void); void r_k_path(void); +void r_k_threads(void); void r_libc_esemaphore(void); void r_libc_string(void); void r_s_printf(void); diff --git a/src/user/lib/thread.S b/src/user/lib/thread.S new file mode 100644 index 0000000..3cd3500 --- /dev/null +++ b/src/user/lib/thread.S @@ -0,0 +1,8 @@ +.section .text +.global chstack +.type chstack, @function +// _Noreturn void chstack(void *arg, void (*fn)(void*), void *esp); +chstack: + mov %rdx, %rsp + call *%rsi + jmp 0 // "exit" diff --git a/src/user/lib/thread.c b/src/user/lib/thread.c new file mode 100644 index 0000000..25d98a9 --- /dev/null +++ b/src/user/lib/thread.c @@ -0,0 +1,11 @@ +#include <camellia/flags.h> +#include <camellia/syscalls.h> +#include <stdlib.h> +#include <user/lib/thread.h> + +void thread_create(int flags, void (*fn)(void*), void *arg) { + if (!_syscall_fork(flags | FORK_SHAREMEM, NULL)) { + void *stack = malloc(4096); + chstack(arg, fn, stack + 4096); + } +} diff --git a/src/user/lib/thread.h b/src/user/lib/thread.h new file mode 100644 index 0000000..0d7376a --- /dev/null +++ b/src/user/lib/thread.h @@ -0,0 +1,4 @@ +#pragma once + +void thread_create(int flags, void (*fn)(void*), void *arg); +_Noreturn void chstack(void *arg, void (*fn)(void*), void *esp); |