diff options
-rw-r--r-- | src/kernel/execbuf.c | 1 | ||||
-rw-r--r-- | src/kernel/main.c | 2 | ||||
-rw-r--r-- | src/kernel/main.h | 1 | ||||
-rw-r--r-- | src/kernel/proc.c | 108 | ||||
-rw-r--r-- | src/kernel/proc.h | 39 | ||||
-rw-r--r-- | src/kernel/syscalls.c | 12 |
6 files changed, 60 insertions, 103 deletions
diff --git a/src/kernel/execbuf.c b/src/kernel/execbuf.c index 8ab0268..7170de2 100644 --- a/src/kernel/execbuf.c +++ b/src/kernel/execbuf.c @@ -1,4 +1,5 @@ #include <camellia/execbuf.h> +#include <camellia/syscalls.h> #include <kernel/execbuf.h> #include <kernel/mem/alloc.h> #include <kernel/panic.h> diff --git a/src/kernel/main.c b/src/kernel/main.c index 03ff177..ef7acee 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -7,7 +7,7 @@ void kmain(struct kmain_info info) { kprintf("loading init...\n"); - process_seed(&info); + process_seed(info.init.at, info.init.size); kprintf("switching...\n"); process_switch_any(); diff --git a/src/kernel/main.h b/src/kernel/main.h index edceb76..45fd85e 100644 --- a/src/kernel/main.h +++ b/src/kernel/main.h @@ -14,5 +14,4 @@ struct kmain_info { }; void kmain(struct kmain_info); - void shutdown(void); diff --git a/src/kernel/proc.c b/src/kernel/proc.c index fd02f33..2e765c7 100644 --- a/src/kernel/proc.c +++ b/src/kernel/proc.c @@ -1,21 +1,25 @@ -#include <camellia/syscalls.h> #include <kernel/arch/generic.h> #include <kernel/execbuf.h> -#include <kernel/main.h> #include <kernel/mem/alloc.h> -#include <kernel/mem/virt.h> #include <kernel/panic.h> #include <kernel/proc.h> #include <kernel/vfs/mount.h> #include <shared/mem.h> #include <stdint.h> -struct process *process_first; +static struct process *process_first = NULL; struct process *process_current; static uint32_t next_pid = 0; -struct process *process_seed(struct kmain_info *info) { + +/** Removes a process from the process tree. */ +static void process_forget(struct process *p); +static _Noreturn void process_switch(struct process *proc); + + +struct process *process_seed(void *data, size_t datalen) { + assert(!process_first); process_first = kmalloc(sizeof *process_first); memset(process_first, 0, sizeof *process_first); process_first->state = PS_RUNNING; @@ -24,6 +28,7 @@ struct process *process_seed(struct kmain_info *info) { process_first->id = next_pid++; // map the stack to the last page in memory + // TODO move to user bootstrap pagedir_map(process_first->pages, (userptr_t)~PAGE_MASK, page_zalloc(1), true, true); process_first->regs.rsp = (userptr_t) ~0xF; @@ -34,9 +39,8 @@ struct process *process_seed(struct kmain_info *info) { // map the init module as rw void __user *init_base = (userptr_t)0x200000; - for (uintptr_t off = 0; off < info->init.size; off += PAGE_SIZE) - pagedir_map(process_first->pages, init_base + off, info->init.at + off, - true, true); + for (uintptr_t off = 0; off < datalen; off += PAGE_SIZE) + pagedir_map(process_first->pages, init_base + off, data + off, true, true); process_first->regs.rcx = (uintptr_t)init_base; // SYSRET jumps to %rcx return process_first; @@ -164,34 +168,26 @@ void process_kill(struct process *p, int ret) { if (p == process_first) shutdown(); } -int process_try2collect(struct process *dead) { - struct process *parent = dead->parent; - int ret = -1; - +void process_try2collect(struct process *dead) { assert(dead && dead->state == PS_DEAD); + assert(!dead->child); - if (!dead->noreap && parent && parent->state != PS_DEAD) { // might be reaped - if (parent->state != PS_WAITS4CHILDDEATH) return -1; - - ret = dead->death_msg; - regs_savereturn(&parent->regs, ret); + struct process *parent = dead->parent; + if (!dead->noreap && parent && parent->state != PS_DEAD) { /* reapable? */ + if (parent->state != PS_WAITS4CHILDDEATH) + return; /* don't reap yet */ + regs_savereturn(&parent->regs, dead->death_msg); process_transition(parent, PS_RUNNING); } - process_free(dead); - return ret; -} - -void process_free(struct process *p) { - assert(p->state == PS_DEAD); - assert(!p->child); - - if (!p->parent) return; - process_forget(p); - kfree(p); + if (dead != process_first) { + process_forget(dead); + kfree(dead); + } } -void process_forget(struct process *p) { +/** Removes a process from the process tree. */ +static void process_forget(struct process *p) { assert(p->parent); if (p->parent->child == p) { @@ -222,24 +218,26 @@ _Noreturn void process_switch_any(void) { if (process_current && process_current->state == PS_RUNNING) process_switch(process_current); - struct process *found = process_find(PS_RUNNING); - if (found) process_switch(found); + for (struct process *p = process_first; p; p = process_next(p)) { + if (p->state == PS_RUNNING) + process_switch(p); + } cpu_pause(); } } struct process *process_next(struct process *p) { - /* is a weird depth-first search, the search order is: + /* depth-first search, the order is: * 1 * / \ * 2 5 * /| |\ * 3 4 6 7 */ - if (!p) return NULL; - if (p->child) return p->child; - if (p->sibling) return p->sibling; + if (!p) return NULL; + if (p->child) return p->child; + if (p->sibling) return p->sibling; /* looking at the diagram above - we're at 4, want to find 5 */ while (!p->sibling) { @@ -249,22 +247,12 @@ struct process *process_next(struct process *p) { return p->sibling; } -struct process *process_find(enum process_state target) { - for (struct process *p = process_first; p; p = process_next(p)) { - if (p->state == target) return p; - } - return NULL; -} - handle_t process_find_free_handle(struct process *proc, handle_t start_at) { - // TODO start_at is a bit of a hack - handle_t handle; - for (handle = start_at; handle < HANDLE_MAX; handle++) { - if (proc->handles[handle] == NULL) - break; + for (handle_t hid = start_at; hid < HANDLE_MAX; hid++) { + if (proc->handles[hid] == NULL) + return hid; } - if (handle >= HANDLE_MAX) handle = -1; - return handle; + return -1; } struct handle *process_handle_get(struct process *p, handle_t id) { @@ -273,24 +261,8 @@ struct handle *process_handle_get(struct process *p, handle_t id) { } void process_transition(struct process *p, enum process_state state) { - enum process_state last = p->state; + assert(p->state != PS_DEAD); + if (state != PS_RUNNING && state != PS_DEAD) + assert(p->state == PS_RUNNING); p->state = state; - switch (state) { - case PS_RUNNING: - assert(last != PS_DEAD); - break; - case PS_DEAD: - // see process_kill - break; - case PS_WAITS4CHILDDEATH: - case PS_WAITS4FS: - case PS_WAITS4REQUEST: - case PS_WAITS4PIPE: - case PS_WAITS4TIMER: - assert(last == PS_RUNNING); - break; - - case PS_LAST: - panic_invalid_state(); - } } diff --git a/src/kernel/proc.h b/src/kernel/proc.h index fb14e35..27327c4 100644 --- a/src/kernel/proc.h +++ b/src/kernel/proc.h @@ -1,10 +1,8 @@ #pragma once -#include <camellia/syscalls.h> #include <kernel/arch/generic.h> #include <kernel/handle.h> -#include <kernel/main.h> -#include <kernel/vfs/mount.h> #include <stdbool.h> +struct vfs_mount; #define HANDLE_MAX 16 @@ -23,18 +21,10 @@ enum process_state { struct process { struct pagedir *pages; struct registers regs; - enum process_state state; - - bool noreap; - - struct process *sibling; - struct process *child; - struct process *parent; - - uint32_t id; // only for debugging, don't expose to userland + struct process *sibling, *child, *parent; - // saved value, meaning depends on .state - union { + enum process_state state; + union { /* saved value, meaning depends on .state */ int death_msg; // PS_DEAD struct { char __user *buf; @@ -53,38 +43,35 @@ struct process { struct process *next; } waits4timer; }; - struct vfs_request *handled_req; + + struct vfs_mount *mount; + struct handle *handles[HANDLE_MAX]; + uint32_t id; /* only for debugging, don't expose to userland */ + bool noreap; /* allocated once, the requests from WAITS4FS get stored here */ struct vfs_request *reqslot; /* vfs_backend controlled (not exclusively) by this process */ struct vfs_backend *controlled; - - struct vfs_mount *mount; + struct vfs_request *handled_req; struct { void *buf; size_t len; size_t pos; } execbuf; - - struct handle *handles[HANDLE_MAX]; }; -extern struct process *process_first; extern struct process *process_current; /** Creates the root process. */ -struct process *process_seed(struct kmain_info *info); +struct process *process_seed(void *data, size_t datalen); struct process *process_fork(struct process *parent, int flags); void process_kill(struct process *proc, int ret); /** Tries to free a process / collect its return value. */ -int process_try2collect(struct process *dead); -void process_free(struct process *); -/** Removes a process from the process tree. */ -void process_forget(struct process *); +void process_try2collect(struct process *dead); /** Switches execution to any running process. */ _Noreturn void process_switch_any(void); @@ -92,8 +79,6 @@ _Noreturn void process_switch_any(void); /** Used for iterating over all processes */ struct process *process_next(struct process *); -struct process *process_find(enum process_state); - handle_t process_find_free_handle(struct process *proc, handle_t start_at); struct handle *process_handle_get(struct process *, handle_t); diff --git a/src/kernel/syscalls.c b/src/kernel/syscalls.c index 68c0241..6bdbf5f 100644 --- a/src/kernel/syscalls.c +++ b/src/kernel/syscalls.c @@ -13,9 +13,8 @@ #include <stdint.h> #define SYSCALL_RETURN(val) do { \ - long ret = (long)val; \ assert(process_current->state == PS_RUNNING); \ - regs_savereturn(&process_current->regs, ret); \ + regs_savereturn(&process_current->regs, (long)(val)); \ return 0; \ } while (0) @@ -33,16 +32,17 @@ long _syscall_await(void) { { if (iter->noreap) continue; has_children = true; - if (iter->state == PS_DEAD) - SYSCALL_RETURN(process_try2collect(iter)); + if (iter->state == PS_DEAD) { + process_try2collect(iter); + return 0; // dummy + } } if (!has_children) { process_transition(process_current, PS_RUNNING); SYSCALL_RETURN(~0); // TODO errno } - - return -1; // dummy + return 0; // dummy } long _syscall_fork(int flags, handle_t __user *fs_front) { |