diff options
| author | Kimplul <kimi.h.kuparinen@gmail.com> | 2024-07-04 19:25:12 +0300 |
|---|---|---|
| committer | Kimplul <kimi.h.kuparinen@gmail.com> | 2024-07-04 19:25:12 +0300 |
| commit | 07c2376702fb3d508d6ffad6b0ce93b83972ad6e (patch) | |
| tree | 9ce46b000f8411fa86118645063b4df05d018dbf /src/uapi/proc.c | |
| parent | 66e7f184a925247bac51aae02d01483faa5454fc (diff) | |
| download | kmi-07c2376702fb3d508d6ffad6b0ce93b83972ad6e.tar.gz kmi-07c2376702fb3d508d6ffad6b0ce93b83972ad6e.zip | |
add zombie and orphan threads
+ Should write this down somewhere but the idea is that when a process
gets killed, it frees all the memory it can, making all threads within
that process orphans. Orphaned threads are assigned to the init
process, which will generally call exit() on each one. Zombie threads
are threads that own some bit of shared data, and whose reference
count is above zero. They may not be swapped to or called, even though
they take up space in thread map and reserve their thread ID.
Diffstat (limited to 'src/uapi/proc.c')
| -rw-r--r-- | src/uapi/proc.c | 100 |
1 files changed, 80 insertions, 20 deletions
diff --git a/src/uapi/proc.c b/src/uapi/proc.c index 1b672ce..3ce808f 100644 --- a/src/uapi/proc.c +++ b/src/uapi/proc.c @@ -10,7 +10,9 @@ #include <kmi/uapi.h> #include <kmi/proc.h> #include <kmi/bits.h> +#include <kmi/power.h> #include <kmi/notify.h> +#include <kmi/orphanage.h> #include <kmi/mem_regions.h> #include <arch/irq.h> @@ -145,24 +147,94 @@ SYSCALL_DEFINE2(spawn)(struct tcb *t, sys_arg_t bin, sys_arg_t interp) * Kill syscall handler. * * @param t Current tcb. - * @param tid Thread to kill. + * @param pid Process to kill. * \todo Implement. * * @return ERR_PERM if not capable to kill, otherwise OK. */ -SYSCALL_DEFINE1(kill)(struct tcb *t, sys_arg_t tid) +SYSCALL_DEFINE1(kill)(struct tcb *t, sys_arg_t pid) { struct tcb *c = get_cproc(t); if (!(has_cap(c->caps, CAP_PROC))) return_args1(t, ERR_PERM); - /** @todo implement */ - /** @todo remember to unregister IRQ handlers */ + struct tcb *r = get_tcb(pid); + if (is_proc(r)) + return_args1(t, ERR_INVAL); + destroy_proc(r); return_args1(t, OK); } /** + * Actual worker of swapping between threads. + * Assumes that both \p t and \p s exist and that \p s isn't a zombie or + * currently running. + * + * @param t Current tcb. + * @param s Thread to swap to. + */ +static void swap(struct tcb *t, struct tcb *s) +{ + /* switch over to new thread */ + use_tcb(s); + + /* if an irq handler is directly swapping to some other thread, + * interpret it as the thread being finished with its critical section */ + enable_irqs(); + + if (!is_rpc(s) && orphan(s)) { + orphanize(s); + return; + } + + /* set return value for current thread */ + set_args1(t, OK); + + /* handle possible queued notification */ + if (s->notify_flags) + notify(s, 0); + + /* no notifications, so get register state for new thread */ + return_args(s, get_args(s)); +} + +/** + * Syscall handler for exit syscall. + * + * @param t Thread that is exiting. + * @param tid Thread to swap to. + * + * @return \ref OK or \ref ERR_INVAL is \p tid is not a thread + * or \ref ERR_NF if \p tid is a zombie + * or \ref ERR_EXT if \p tid is currently running. + */ +SYSCALL_DEFINE1(exit)(struct tcb *t, sys_arg_t tid) +{ + if (tid != 0) { + struct tcb *s = get_tcb(tid); + if (!s) + return_args1(t, ERR_INVAL); + + if (zombie(s)) + return_args1(t, ERR_NF); + + if (running(s)) + return_args1(t, ERR_EXT); + + + swap(t, s); + } + + destroy_thread(t); + + if (tid == 0) { + enable_irqs(); + sleep(); + } +} + +/** * Swap syscall handler. * * \todo Implement. @@ -183,23 +255,11 @@ SYSCALL_DEFINE1(swap)(struct tcb *t, sys_arg_t tid){ if (!s) return_args1(t, ERR_INVAL); + if (zombie(s)) + return_args1(t, ERR_NF); + if (running(s)) return_args1(t, ERR_EXT); - /* switch over to new thread */ - use_tcb(s); - - /* set return value for current thread */ - set_args1(t, OK); - - /* if an irq handler is directly swapping to some other thread, - * interpret it as the thread being finished with its critical section */ - enable_irqs(); - - /* handle possible queued notification */ - if (s->notify_flags) - notify(s, 0); - - /* no notifications, so get register state for new thread */ - return_args(s, get_args(s)); + return swap(t, s); } |
