From bc600ecc3bdf0f189861dfb840f70c2339a7a853 Mon Sep 17 00:00:00 2001 From: Kimplul Date: Fri, 24 May 2024 13:24:27 +0300 Subject: rename common to src + I keep starting to type src and wondering why autocomplete won't work, I guess src is just uncounciously a better name --- common/tcb.c | 310 ----------------------------------------------------------- 1 file changed, 310 deletions(-) delete mode 100644 common/tcb.c (limited to 'common/tcb.c') diff --git a/common/tcb.c b/common/tcb.c deleted file mode 100644 index c0f82cc..0000000 --- a/common/tcb.c +++ /dev/null @@ -1,310 +0,0 @@ -/* SPDX-License-Identifier: copyleft-next-0.3.1 */ -/* Copyright 2021 - 2022, Kim Kuparinen < kimi.h.kuparinen@gmail.com > */ - -/** - * @file tcb.c - * Thread control block handling implementation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -/* arguably exessively many globals... */ -/** Thread ID to start looking from when allocating new ID. */ -static id_t start_tid = 0; - -/** Total number of possible thread IDs. */ -static id_t num_tids; - -/** Pointer to array of \ref tcb structures. Length of the array is \c num_tids.*/ -static struct tcb **tcbs; - -/** - * Array of thread control block associated with each cpu. - * - * \todo If we ever support systems with massive amounts of cpus, this should probably - * be allocated at runtime. - */ -static struct tcb *__cpu_tcb[MAX_CPUS] = { 0 }; - -void init_tcbs() -{ - /* MM_O1 is 2MiB on riscv64, so 262144 different possible thread ids. - * Should be enough, if we're really strapped for memory I might try - * something smaller but this is fine for now. */ - tcbs = (struct tcb **)alloc_page(MM_O1); - num_tids = order_size(MM_O1) / sizeof(struct tcb *); - catastrophic_assert(is_powerof2(num_tids)); - memset(tcbs, 0, order_size(MM_O1)); -} - -void destroy_tcbs() -{ - free_page(MM_O1, (pm_t)tcbs); -} - -/** - * Allocate a new thread ID. - * - * @param t Thread to allocate new ID to. - * @return Allocated ID. - */ -static id_t __alloc_tid(struct tcb *t) -{ - id_t stop_tid = start_tid - 1; - /** \todo this would need some locking or something... */ - for (id_t i = start_tid;; ++i) { - if (i <= 0) - i = 1; - - /* we're completely full */ - if (i == stop_tid) - return ERR_NF; - - if (get_tcb(i) || i == 0) - continue; - - tcbs[i & (num_tids - 1)] = t; - start_tid = i + 1; - return i; - } - - return ERR_NF; -} - -/** - * Setup thread stack. - * - * @param t Thread to setup stack for. - * @param bytes Minimum size of stack. - * @return Base of allocated stack. - */ -static vm_t __setup_thread_stack(struct tcb *t, size_t bytes) -{ - return alloc_uvmem(t, bytes, VM_V | VM_R | VM_W | VM_U); -} - -stat_t alloc_stack(struct tcb *t) -{ - /* get parent process */ - struct tcb *p = get_tcb(t->eid); - - t->thread_stack = __setup_thread_stack(p, __thread_stack_size); - if (!t->thread_stack) - return ERR_OOMEM; - - /** \todo this only allows for a global stack size, what if a user wants - * per thread stack sizes? */ - t->thread_stack_top = t->thread_stack + __thread_stack_size; - return OK; -} - -struct tcb *create_thread(struct tcb *p) -{ - hard_assert(tcbs, 0); - - vm_t bottom = alloc_page(KERNEL_STACK_PAGE_ORDER); - /* move tcb to top of kernel stack, keeping alignment in check - * (hopefully) */ - /** \todo check alignment */ - struct tcb *t = (struct tcb *)align_down( - bottom + order_size(MM_O0) - sizeof(struct tcb), sizeof(long)); - memset(t, 0, sizeof(struct tcb)); - - id_t tid = __alloc_tid(t); - tcbs[tid] = t; - t->tid = tid; - t->dead = false; - - if (likely(p)) { - t->pid = p->pid; - /** @todo I'm assuming two threads can share the same vmem - * structure, this works on riscv but in the event that other - * systems don't we can easily turn this into a clone_uvmem. */ - t->proc.vmem = p->proc.vmem; - } else { - init_uvmem(t, UVMEM_START, UVMEM_END); - t->proc.vmem = create_vmem(); - t->pid = t->tid; - t->rid = t->tid; - p = t; - } - - t->eid = t->pid; - t->rid = p->rid; - t->rpc.vmem = create_vmem(); - setup_rpc_stack(t); - reference_proc(p); - - t->regs = (vm_t)t; - - set_canary(t); - return t; -} - -/** - * Copy process. - * - * @param p Parent process. - * @param n New process. - * @return \ref OK. - */ -static stat_t __copy_proc(struct tcb *p, struct tcb *n) -{ - /** @todo setup rpc stack stuff */ - /** @todo I think keeping track of userspace stack stuff is unnecessary, - * unless we want unlimited stack size but that sounds dumb. Anycase, we - * need to duplicate stack info, whatever we do. */ - n->exec = p->exec; - n->callback = p->callback; - n->thread_stack = p->thread_stack; - n->thread_stack_top = p->thread_stack_top; - - clone_regs(n, p); - copy_caps(n->caps, p->caps); - return clone_mem_regions(n, p); -} - -struct tcb *create_proc(struct tcb *p) -{ - hard_assert(tcbs, 0); - - /* create a new thread outside the current process */ - struct tcb *n = create_thread(NULL); - if (!n) - return 0; - - if (p) - __copy_proc(p, n); /* we have a parent thread */ - - return n; -} - -/** - * Destroy data associated with thread. - * - * @param t Thread whose data to destroy. - * @return \ref OK. - */ -static stat_t __destroy_thread_data(struct tcb *t) -{ - /* free rpc vmem */ - destroy_vmem(t->rpc.vmem); - - /* 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; -} - -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; - - /* remove reference to root process */ - unreference_proc(get_rproc(t)); - - return __destroy_thread_data(t); -} - -stat_t destroy_proc(struct tcb *p) -{ - hard_assert(tcbs, ERR_NOINIT); - hard_assert(is_proc(p), ERR_INVAL); - - p->dead = true; - /* unreference ourselves */ - unreference_proc(p); - - catastrophic_assert(destroy_uvmem(p)); - return __destroy_thread_data(p); -} - -void reference_proc(struct tcb *p) -{ - hard_assert(is_proc(p), RETURN_VOID); - p->refcount++; -} - -void unreference_proc(struct tcb *p) -{ - 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 */ - } -} - -/* weak to allow optimisation on risc-v, but provide fallback for future */ -__weak struct tcb *cur_tcb() -{ - return cpu_tcb(cpu_id()); -} - -struct tcb *cpu_tcb(id_t cpu_id) -{ - return __cpu_tcb[cpu_id]; -} - -struct tcb *cur_proc() -{ - struct tcb *t = cur_tcb(); - return get_tcb(t->pid); -} - -struct tcb *eff_proc() -{ - struct tcb *t = cur_tcb(); - return get_tcb(t->eid); -} - -void use_tcb(struct tcb *t) -{ - cpu_assign(t); - - __cpu_tcb[t->cpu_id] = t; - - use_vmem(t->proc.vmem); -} - -struct tcb *get_tcb(id_t tid) -{ - hard_assert(tcbs, 0); - - if (tid <= 0) - return NULL; - - return tcbs[tid & (num_tids - 1)]; -} - -void set_return(struct tcb *t, vm_t v) -{ - t->exec = v; -} - -bool running(struct tcb *t) -{ - return cpu_tcb(t->cpu_id) == t; -} -- cgit v1.3