diff options
-rw-r--r-- | src/init/main.c | 3 | ||||
-rw-r--r-- | src/kernel/proc.c | 67 | ||||
-rw-r--r-- | src/kernel/proc.h | 3 | ||||
-rw-r--r-- | src/kernel/vfs/request.c | 2 |
4 files changed, 59 insertions, 16 deletions
diff --git a/src/init/main.c b/src/init/main.c index 3460417..ef67958 100644 --- a/src/init/main.c +++ b/src/init/main.c @@ -57,7 +57,6 @@ int main(void) { if (__stdout < 0) __stdout = _syscall_open(argify("/vga_tty")); _syscall_await(); - printf("init: something quit\n"); - + printf("init: quitting\n"); _syscall_exit(0); } diff --git a/src/kernel/proc.c b/src/kernel/proc.c index 611fd81..9e8e4c5 100644 --- a/src/kernel/proc.c +++ b/src/kernel/proc.c @@ -169,9 +169,16 @@ void process_transition(struct process *p, enum process_state state) { switch (state) { case PS_RUNNING: assert(last != PS_DEAD && last != PS_DEADER); + if (p->deathbed) + process_kill(p, -1); + /* TODO return something to warn caller if deathbedded, to prevent + * use after free + * + * alternatively assert(!p->deathbed); and move the responsibility + * to the caller */ break; case PS_DEAD: - assert(last == PS_RUNNING); + // see process_kill break; case PS_DEADER: assert(last == PS_DEAD); @@ -188,13 +195,20 @@ void process_transition(struct process *p, enum process_state state) { } } -void process_kill(struct process *proc, int ret) { - // TODO kill children - if (proc->controlled) { - proc->controlled->potential_handlers--; - if (proc->controlled->potential_handlers == 0) { +void process_kill(struct process *p, int ret) { + if (p->state == PS_DEAD || p->state == PS_DEADER) return; + + if (p->handled_req) { + vfs_request_cancel(p->handled_req, ret); + p->handled_req = NULL; + } + if (p->controlled) { + // code stink: i don't like how handling controlled backends is split + // between this if and the switch lower down + p->controlled->potential_handlers--; + if (p->controlled->potential_handlers == 0) { // orphaned - struct vfs_request *q = proc->controlled->queue; + struct vfs_request *q = p->controlled->queue; while (q) { struct vfs_request *q2 = q->queue_next; vfs_request_cancel(q, ret); @@ -202,13 +216,40 @@ void process_kill(struct process *proc, int ret) { } } } - if (proc->handled_req) { - vfs_request_cancel(proc->handled_req, ret); + + // TODO VULN unbounded recursion + for (struct process *c = p->child; c; c = c->sibling) + process_kill(c, -1); + + switch (p->state) { + case PS_RUNNING: + case PS_WAITS4CHILDDEATH: + break; + + case PS_WAITS4FS: + // if the request wasn't accepted we could just remove this process from the queue + case PS_WAITS4IRQ: + /* the system doesn't shut down until it receives one of each of the interrupts it's waiting for + * more broadly: killing processes stuck on long io calls doesn't free up the drivers + * TODO add a syscall for checking if a request is still valid, to bail early + * ( not needed for our kernel drivers, but we need feature parity ) + */ + p->deathbed = true; + return; + + case PS_WAITS4REQUEST: + assert(p->controlled); + if (p->controlled->handler == p) + p->controlled->handler = NULL; + break; + + default: + kprintf("process_kill unexpected state 0x%x\n", p->state); + panic_invalid_state(); } - process_transition(proc, PS_DEAD); - proc->death_msg = ret; - process_try2collect(proc); - if (proc == process_first) shutdown(); + process_transition(p, PS_DEAD); + p->death_msg = ret; + process_try2collect(p); } int process_try2collect(struct process *dead) { diff --git a/src/kernel/proc.h b/src/kernel/proc.h index f0bae50..255a9af 100644 --- a/src/kernel/proc.h +++ b/src/kernel/proc.h @@ -3,6 +3,7 @@ #include <kernel/handle.h> #include <kernel/vfs/mount.h> #include <shared/syscalls.h> +#include <stdbool.h> enum process_state { PS_RUNNING, @@ -20,6 +21,8 @@ struct process { struct registers regs; enum process_state state; + bool deathbed; // kill instead of switching to PS_RUNNING + struct process *sibling; struct process *child; struct process *parent; diff --git a/src/kernel/vfs/request.c b/src/kernel/vfs/request.c index 625448d..b3769cf 100644 --- a/src/kernel/vfs/request.c +++ b/src/kernel/vfs/request.c @@ -92,8 +92,8 @@ int vfs_request_finish(struct vfs_request *req, int ret) { kfree(req->input.buf_kern); assert(req->caller->state == PS_WAITS4FS || req->caller->state == PS_WAITS4IRQ); - process_transition(req->caller, PS_RUNNING); regs_savereturn(&req->caller->regs, ret); + process_transition(req->caller, PS_RUNNING); return ret; } |