aboutsummaryrefslogtreecommitdiff
path: root/src/tcb.c
diff options
context:
space:
mode:
authorKimplul <kimi.h.kuparinen@gmail.com>2024-07-04 19:25:12 +0300
committerKimplul <kimi.h.kuparinen@gmail.com>2024-07-04 19:25:12 +0300
commit07c2376702fb3d508d6ffad6b0ce93b83972ad6e (patch)
tree9ce46b000f8411fa86118645063b4df05d018dbf /src/tcb.c
parent66e7f184a925247bac51aae02d01483faa5454fc (diff)
downloadkmi-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/tcb.c')
-rw-r--r--src/tcb.c51
1 files changed, 42 insertions, 9 deletions
diff --git a/src/tcb.c b/src/tcb.c
index c0f82cc..8280deb 100644
--- a/src/tcb.c
+++ b/src/tcb.c
@@ -7,6 +7,7 @@
*/
#include <kmi/tcb.h>
+#include <kmi/ipi.h>
#include <kmi/mem.h>
#include <kmi/conf.h>
#include <kmi/pmem.h>
@@ -200,15 +201,23 @@ struct tcb *create_proc(struct tcb *p)
*/
static stat_t __destroy_thread_data(struct tcb *t)
{
+ catastrophic_assert(t->refcount == 0);
+
+ /* free memory backing rpc stack */
+ destroy_rpc_stack(t);
+
/* free rpc vmem */
destroy_vmem(t->rpc.vmem);
+ /* remove ourselves from the thread pool */
+ tcbs[t->tid] = 0;
+
+ /* forcefully free last struggling bits of memory */
+ destroy_uvmem(t);
+
/* free associated kernel stack and the structure itself */
vm_t bottom = align_down((vm_t)t, order_size(MM_O0));
free_page(MM_O0, (pm_t)bottom);
-
- /** \todo free stacks */
-
return OK;
}
@@ -217,14 +226,19 @@ stat_t destroy_thread(struct tcb *t)
hard_assert(tcbs, ERR_NOINIT);
hard_assert(!is_proc(t), ERR_INVAL);
- /* remove thread id from list */
- /** @todo what about if thread is in rpc? should it rather just be
- * marked dead? */
- tcbs[t->tid] = 0;
+ /* mark us as zombies */
+ t->rid = 0;
/* remove reference to root process */
unreference_proc(get_rproc(t));
+ unqueue_ipi(t);
+
+ /* someone still relies on us existing, don't actually free thread data
+ * quite yet */
+ if (t->refcount)
+ return OK;
+
return __destroy_thread_data(t);
}
@@ -238,22 +252,31 @@ stat_t destroy_proc(struct tcb *p)
unreference_proc(p);
catastrophic_assert(destroy_uvmem(p));
- return __destroy_thread_data(p);
+
+ /* don't destroy thread data just yet, let the thread destroy itself
+ * later */
+ return OK;
}
void reference_proc(struct tcb *p)
{
+ if (!p)
+ return;
+
hard_assert(is_proc(p), RETURN_VOID);
p->refcount++;
}
void unreference_proc(struct tcb *p)
{
+ if (!p)
+ return;
+
hard_assert(is_proc(p), RETURN_VOID);
p->refcount--;
if (p->dead && p->refcount == 0) {
dbg("thread %d is completely destroyed\n", p->tid);
- /** @todo actually destroy */
+ __destroy_thread_data(p);
}
}
@@ -308,3 +331,13 @@ bool running(struct tcb *t)
{
return cpu_tcb(t->cpu_id) == t;
}
+
+bool zombie(struct tcb *t)
+{
+ /* we shouldn't see any NULLs but they're effectively the same thing */
+ if (!t)
+ return true;
+
+ /* thread doesn't belong to any process, a zombie */
+ return t->rid == 0;
+}