From b6d2cfb9b3f08dd7627fe1924449ff06c548efbe Mon Sep 17 00:00:00 2001 From: Mark Date: Mon, 3 Feb 2020 13:59:00 +0200 Subject: [PATCH] Better cleanup of dead threads --- sys/sched.c | 33 +++++++++++++++++++++++ sys/thread.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 107 insertions(+), 1 deletion(-) diff --git a/sys/sched.c b/sys/sched.c index f2714fb..9dd78e0 100644 --- a/sys/sched.c +++ b/sys/sched.c @@ -1,4 +1,6 @@ #include "sys/amd64/context.h" +#include "sys/amd64/mm/pool.h" +#include "sys/amd64/mm/phys.h" #include "sys/amd64/hw/irq.h" #include "sys/amd64/hw/idt.h" #include "sys/user/signum.h" @@ -8,6 +10,7 @@ #include "sys/thread.h" #include "sys/sched.h" #include "sys/debug.h" +#include "sys/heap.h" #include "sys/mm.h" void yield(void); @@ -146,6 +149,12 @@ void sched_debug_cycle(uint64_t delta_ms) { struct thread *thr = queue_head; extern struct thread user_init; + struct heap_stat st; + struct amd64_phys_stat phys_st; + struct amd64_pool_stat pool_st; + + kdebug("--- DEBUG_CYCLE ---\n"); + debugs(DEBUG_DEFAULT, "Process tree:\n"); sched_debug_tree(DEBUG_DEFAULT, &user_init, 0); @@ -167,6 +176,30 @@ void sched_debug_cycle(uint64_t delta_ms) { } else { kdebug("--- IDLE\n"); } + + heap_stat(heap_global, &st); + kdebug("Heap stat:\n"); + kdebug("Allocated blocks: %u\n", st.alloc_count); + kdebug("Used %S, free %S, total %S\n", st.alloc_size, st.free_size, st.total_size); + + amd64_phys_stat(&phys_st); + kdebug("Physical memory:\n"); + kdebug("Used %S (%u), free %S (%u), ceiling %p\n", + phys_st.pages_used * 0x1000, + phys_st.pages_used, + phys_st.pages_free * 0x1000, + phys_st.pages_free, + phys_st.limit); + + amd64_mm_pool_stat(&pool_st); + kdebug("Paging pool:\n"); + kdebug("Used %S (%u), free %S (%u)\n", + pool_st.pages_used * 0x1000, + pool_st.pages_used, + pool_st.pages_free * 0x1000, + pool_st.pages_free); + + kdebug("--- ----------- ---\n"); } void yield(void) { diff --git a/sys/thread.c b/sys/thread.c index 129b77f..cefac08 100644 --- a/sys/thread.c +++ b/sys/thread.c @@ -57,6 +57,24 @@ static void thread_add(struct thread *thr) { threads_all_head = thr; } +static void thread_remove(struct thread *thr) { + struct thread *prev = thr->g_prev; + struct thread *next = thr->g_next; + + if (prev) { + prev->g_next = next; + } else { + threads_all_head = next; + } + + if (next) { + next->g_prev = prev; + } + + thr->g_next = NULL; + thr->g_prev = NULL; +} + //// static void thread_ioctx_empty(struct thread *thr) { @@ -113,6 +131,32 @@ struct thread *thread_child(struct thread *of, pid_t pid) { return NULL; } +void thread_unchild(struct thread *thr) { + struct thread *par = thr->parent; + _assert(par); + + struct thread *p = NULL; + struct thread *c = par->first_child; + int found = 0; + + while (c) { + if (c == thr) { + found = 1; + if (p) { + p->next_child = thr->next_child; + } else { + par->first_child = thr->next_child; + } + break; + } + + p = c; + c = c->next_child; + } + + _assert(found); +} + void thread_cleanup(struct thread *thr) { _assert(thr); // Leave only the system context required for hierachy tracking and error code/pid @@ -136,6 +180,30 @@ void thread_cleanup(struct thread *thr) { mm_space_release(thr->space); } +void thread_free(struct thread *thr) { + _assert(thr->flags & THREAD_STOPPED); + _assert(thr->flags & THREAD_EMPTY); + + // Free kstack + for (size_t i = 0; i < thr->data.rsp0_size / MM_PAGE_SIZE; ++i) { + amd64_phys_free(MM_PHYS(i * MM_PAGE_SIZE + thr->data.rsp0_base)); + } + + // Free page directory (if not mm_kernel) + if (thr->space != mm_kernel) { + // Make sure we don't shoot a leg off + uintptr_t cr3; + asm volatile ("movq %%cr3, %0":"=a"(cr3)); + _assert(MM_VIRTUALIZE(cr3) != (uintptr_t) thr->space); + + mm_space_free(thr->space); + } + + // Free thread itself + memset(thr, 0, sizeof(struct thread)); + kfree(thr); +} + int thread_init(struct thread *thr, uintptr_t entry, void *arg, int user) { uintptr_t stack_pages = amd64_phys_alloc_contiguous(2); _assert(stack_pages != MM_NADDR); @@ -552,11 +620,16 @@ int sys_waitpid(pid_t pid, int *status) { thread_check_signal(thr, 0); } + // Make sure no platform context remains + _assert(chld->flags & THREAD_EMPTY); + if (status) { *status = chld->exit_status; } - // TODO: Cleanup the child here + thread_unchild(chld); + thread_remove(chld); + thread_free(chld); return 0; }