diff options
Diffstat (limited to 'src/kernel/proc.c')
-rw-r--r-- | src/kernel/proc.c | 190 |
1 files changed, 90 insertions, 100 deletions
diff --git a/src/kernel/proc.c b/src/kernel/proc.c index 3233725..ed257fd 100644 --- a/src/kernel/proc.c +++ b/src/kernel/proc.c @@ -74,6 +74,92 @@ struct process *process_fork(struct process *parent, int flags) { return child; } +void process_kill(struct process *p, int ret) { + if (p->state != PS_DEAD) { + if (p->handled_req) { + vfsreq_finish(p->handled_req, -1); + p->handled_req = NULL; + } + + if (p->controlled) { + // TODO vfs_backend_user_handlerdown + assert(p->controlled->potential_handlers > 0); + p->controlled->potential_handlers--; + if (p->controlled->potential_handlers == 0) { + // orphaned + struct vfs_request *q = p->controlled->queue; + while (q) { + struct vfs_request *q2 = q->queue_next; + vfsreq_finish(q, -1); + q = q2; + } + p->controlled->queue = NULL; + } + if (p->controlled->user.handler == p) { + assert(p->state == PS_WAITS4REQUEST); + p->controlled->user.handler = NULL; + } + + vfs_backend_refdown(p->controlled); + p->controlled = NULL; + } + + if (p->state == PS_WAITS4FS) + p->waits4fs.req->caller = NULL; + + for (handle_t h = 0; h < HANDLE_MAX; h++) + handle_close(p->handles[h]); + + vfs_mount_remref(p->mount); + p->mount = NULL; + + process_transition(p, PS_DEAD); + p->death_msg = ret; + + if (p->parent) + pagedir_free(p->pages); // TODO put init's pages in the allocator + + // TODO VULN unbounded recursion + struct process *c2; + for (struct process *c = p->child; c; c = c2) { + c2 = c->sibling; + process_kill(c, -1); + } + } + + assert(!p->child); + process_try2collect(p); + + if (p == process_first) shutdown(); +} + +int process_try2collect(struct process *dead) { + struct process *parent = dead->parent; + int ret = -1; + + assert(dead && dead->state == PS_DEAD); + + 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); + 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); +} + void process_forget(struct process *p) { assert(p->parent); @@ -90,15 +176,6 @@ void process_forget(struct process *p) { } } -void process_free(struct process *p) { - assert(p->state == PS_DEAD); - assert(!p->child); - - if (!p->parent) return; - process_forget(p); - kfree(p); -} - static _Noreturn void process_switch(struct process *proc) { assert(proc->state == PS_RUNNING); process_current = proc; @@ -138,23 +215,13 @@ struct process *process_next(struct process *p) { } struct process *process_find(enum process_state target) { - struct process *result = NULL; - process_find_multiple(target, &result, 1); - return result; -} - -size_t process_find_multiple(enum process_state target, struct process **buf, size_t max) { - size_t i = 0; - for (struct process *p = process_first; - i < max && p; - p = process_next(p)) - { - if (p->state == target) buf[i++] = p; + for (struct process *p = process_first; p; p = process_next(p)) { + if (p->state == target) return p; } - return i; + return NULL; } -handle_t process_find_handle(struct process *proc, handle_t start_at) { +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++) { @@ -194,80 +261,3 @@ void process_transition(struct process *p, enum process_state state) { panic_invalid_state(); } } - -void process_kill(struct process *p, int ret) { - if (p->state != PS_DEAD) { - if (p->handled_req) { - vfsreq_finish(p->handled_req, -1); - p->handled_req = NULL; - } - - if (p->controlled) { - // TODO vfs_backend_user_handlerdown - assert(p->controlled->potential_handlers > 0); - p->controlled->potential_handlers--; - if (p->controlled->potential_handlers == 0) { - // orphaned - struct vfs_request *q = p->controlled->queue; - while (q) { - struct vfs_request *q2 = q->queue_next; - vfsreq_finish(q, -1); - q = q2; - } - p->controlled->queue = NULL; - } - if (p->controlled->user.handler == p) { - assert(p->state == PS_WAITS4REQUEST); - p->controlled->user.handler = NULL; - } - - vfs_backend_refdown(p->controlled); - p->controlled = NULL; - } - - if (p->state == PS_WAITS4FS) - p->waits4fs.req->caller = NULL; - - for (handle_t h = 0; h < HANDLE_MAX; h++) - handle_close(p->handles[h]); - - vfs_mount_remref(p->mount); - p->mount = NULL; - - process_transition(p, PS_DEAD); - p->death_msg = ret; - - if (p->parent) - pagedir_free(p->pages); // TODO put init's pages in the allocator - - // TODO VULN unbounded recursion - struct process *c2; - for (struct process *c = p->child; c; c = c2) { - c2 = c->sibling; - process_kill(c, -1); - } - } - - assert(!p->child); - process_try2collect(p); - - if (p == process_first) shutdown(); -} - -int process_try2collect(struct process *dead) { - struct process *parent = dead->parent; - int ret = -1; - - assert(dead && dead->state == PS_DEAD); - - 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); - process_transition(parent, PS_RUNNING); - } - - process_free(dead); - return ret; -} |