summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/init/main.c3
-rw-r--r--src/kernel/proc.c67
-rw-r--r--src/kernel/proc.h3
-rw-r--r--src/kernel/vfs/request.c2
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;
}