diff options
Diffstat (limited to 'src/kernel/proc.c')
-rw-r--r-- | src/kernel/proc.c | 129 |
1 files changed, 54 insertions, 75 deletions
diff --git a/src/kernel/proc.c b/src/kernel/proc.c index 96386df..0ce0f50 100644 --- a/src/kernel/proc.c +++ b/src/kernel/proc.c @@ -10,16 +10,12 @@ #include <stdint.h> static Proc *proc_first = NULL; -static Proc *proc_forgotten = NULL; /* linked list */ +static Proc *dead_leaves = NULL; /* linked list */ Proc *proc_cur; static uint32_t next_pid = 1; - -/** Removes a process from the process tree. */ -static void proc_forget(Proc *p); -static void proc_free_forgotten(void); - +static void proc_prune_leaves(void); Proc *proc_seed(void *data, size_t datalen) { assert(!proc_first); @@ -305,35 +301,14 @@ void proc_kill(Proc *p, int ret) { proc_setstate(p, PS_TOMBSTONE); } } - if (p == proc_first && p->child) { - _panic("init killed prematurely"); - } - proc_tryreap(p); - if (p == proc_first) { - proc_free_forgotten(); - shutdown(); - } -} - -void proc_filicide(Proc *parent, int ret) { - /* Kill deeper descendants. */ - Proc *child, *child2; - for (child = parent->child; child; child = child2) { - child2 = child->sibling; - - // O(n^2), but doable in linear time - while (child->child) { - Proc *p = child->child; - while (p->child) p = p->child; - p->noreap = true; - proc_kill(p, ret); - } - - if (proc_alive(child)) { - proc_kill(child, ret); + proc_prune_leaves(); + if (p->child) { + _panic("init killed prematurely"); } - child = NULL; + shutdown(); + } else { + proc_tryreap(p); } } @@ -368,30 +343,36 @@ void proc_tryreap(Proc *dead) { dead->noreap = true; } - assert(dead->state == PS_TOMBSTONE); - for (Proc *p = dead->child; p; p = p->sibling) { - assert(p->state != PS_TOREAP); - } - if (dead->child) { + assert(dead->state == PS_TOMBSTONE); + for (Proc *p = dead->child; p; p = p->sibling) { + assert(p->state != PS_TOREAP); + } + Proc *p = dead->child; - while (p->child) p = p->child; + while (p->child) { + p = p->child; + } if (p->state == PS_TOREAP) { assert(proc_alive(p->parent)); } else { - assert(proc_alive(p)); + assert(proc_alive(p) || p->state == PS_DEADLEAF); } + return; /* keep the tombstone */ } + if (!parent) return; /* not applicable to init */ assert(dead->refcount == 0); - if (parent) { /* not applicable to init */ - proc_forget(dead); - // TODO force gcc to optimize the tail call here - if (!proc_alive(parent)) { - proc_tryreap(parent); - } + if (dead->state == PS_TOMBSTONE) { + proc_setstate(dead, PS_DEADLEAF); + /* not altering the process tree right now to prevent breaking tree + * traversals */ + dead->deadleaf_next = dead_leaves; + dead_leaves = dead; + } else { + assert(dead->state == PS_DEADLEAF); } } @@ -417,44 +398,42 @@ void proc_intr(Proc *p) { p->regs.rsp = sp; } -/** Removes a process from the process tree. */ -static void proc_forget(Proc *p) { - assert(p->parent); - assert(p->parent->child); - assert(!p->child); +static void proc_prune_leaves(void) { + while (dead_leaves) { + Proc *p = dead_leaves; + Proc *parent = p->parent; - if (p->parent->child == p) { - p->parent->child = p->sibling; - } else { - // this would be simpler if siblings were a doubly linked list - Proc *prev = p->parent->child; - while (prev->sibling != p) { - prev = prev->sibling; - assert(prev); - } - prev->sibling = p->sibling; - } + dead_leaves = p->deadleaf_next; + assert(p->state == PS_DEADLEAF); - p->parent = NULL; - p->sibling = proc_forgotten; - proc_forgotten = p; - proc_setstate(p, PS_FORGOTTEN); -} - -static void proc_free_forgotten(void) { - while (proc_forgotten) { - Proc *p = proc_forgotten; - proc_forgotten = p->sibling; + assert(p->parent); + assert(p->parent->child); + assert(!p->child); + if (p->parent->child == p) { + p->parent->child = p->sibling; + } else { + // this would be simpler if siblings were a doubly linked list + Proc *prev = p->parent->child; + while (prev->sibling != p) { + prev = prev->sibling; + assert(prev); + } + prev->sibling = p->sibling; + } proc_setstate(p, PS_FREED); kfree(p); + + if (!proc_alive(parent)) { + proc_tryreap(parent); + } } } _Noreturn void proc_switch_any(void) { /* At this point there will be no leftover pointers to forgotten * processes on the stack, so it's safe to free them. */ - proc_free_forgotten(); + proc_prune_leaves(); for (;;) { Proc *p = NULL; @@ -581,8 +560,8 @@ hid_t proc_handle_put(Proc *p, Handle *h) { void proc_setstate(Proc *p, enum proc_state state) { assert(p->state != PS_FREED); if (state == PS_FREED) { - assert(p->state == PS_FORGOTTEN); - } else if (state == PS_FORGOTTEN) { + assert(p->state == PS_DEADLEAF); + } else if (state == PS_DEADLEAF) { assert(p->state == PS_TOMBSTONE); } else if (state == PS_TOMBSTONE) { assert(p->state == PS_TOREAP || p->state == PS_DYING); |