diff options
| author | Kimplul <kimi.h.kuparinen@gmail.com> | 2022-05-22 15:05:39 +0300 |
|---|---|---|
| committer | Kimplul <kimi.h.kuparinen@gmail.com> | 2022-05-22 15:05:39 +0300 |
| commit | 5793a61eb824a7b97e9bab5913b595a778205cef (patch) | |
| tree | f31931b924058cb6474b80cd02472940ad8cfcd5 /common | |
| parent | a4851206bef5ceecef18b3fde5be6918a67cca21 (diff) | |
| download | kmi-5793a61eb824a7b97e9bab5913b595a778205cef.tar.gz kmi-5793a61eb824a7b97e9bab5913b595a778205cef.zip | |
improved tcb handling in preparation for processes
Diffstat (limited to 'common')
| -rw-r--r-- | common/mem_regions.c | 34 | ||||
| -rw-r--r-- | common/proc.c | 7 | ||||
| -rw-r--r-- | common/tcb.c | 98 | ||||
| -rw-r--r-- | common/uapi/dispatch.c | 3 | ||||
| -rw-r--r-- | common/uapi/ipc.c | 17 | ||||
| -rw-r--r-- | common/vmem.c | 51 |
6 files changed, 164 insertions, 46 deletions
diff --git a/common/mem_regions.c b/common/mem_regions.c index bbc894e..9f8f98e 100644 --- a/common/mem_regions.c +++ b/common/mem_regions.c @@ -6,7 +6,6 @@ #define mark_region_used(r) __set_bit(r, MR_USED) #define mark_region_unused(r) __clear_bit(r, MR_USED) -#define region_used(r) __is_set(r, MR_USED) /* pretty major slowdown when we get to some really massive numbers, not * entirely sure why. Will need to check up on this at some point, have I @@ -121,17 +120,22 @@ static void __destroy_region(struct sp_node *n) if (!n) return; - __destroy_region(sp_left(n)); - __destroy_region(sp_right(n)); + if (sp_left(n)) + __destroy_region(sp_left(n)); + + if (sp_right(n)) + __destroy_region(sp_right(n)); struct mem_region *m = mem_container(n); free_mem_node(m); } -void destroy_region(struct mem_region_root *r) +stat_t destroy_region(struct mem_region_root *r) { __destroy_region(sp_root(&r->free_regions)); __destroy_region(sp_root(&r->used_regions)); + /* TODO: error checking? */ + return OK; } /* interestingly this is now the main bottleneck :D @@ -245,6 +249,18 @@ struct mem_region *find_free_region(struct mem_region_root *r, size_t size, return quick_best; } +struct mem_region *find_first_region(struct mem_region_root *r) +{ + /* get used region with smallest address, likely also close to the start + * of the linked list */ + struct mem_region *m = find_closest_used_region(r, 0); + while (m->prev) { + m = m->prev; + } + + return m; +} + static vm_t __partition_region(struct mem_region_root *r, struct mem_region *m, size_t pages, size_t align, vmflags_t flags) { @@ -332,7 +348,7 @@ vm_t alloc_fixed_region(struct mem_region_root *r, vm_t start, size_t size, } /* if region is already in use, forget it */ - if (region_used(m->flags)) + if (is_region_used(m)) return 0; /* region is too small */ @@ -346,11 +362,11 @@ vm_t alloc_fixed_region(struct mem_region_root *r, vm_t start, size_t size, static void __try_coalesce_prev(struct mem_region_root *r, struct mem_region *m) { while (m) { - if (!m || region_used(m->flags)) + if (!m || is_region_used(m)) return; struct mem_region *p = m->prev; - if (!p || region_used(p->flags)) + if (!p || is_region_used(p)) return; m->start = p->start; @@ -369,11 +385,11 @@ static void __try_coalesce_prev(struct mem_region_root *r, struct mem_region *m) static void __try_coalesce_next(struct mem_region_root *r, struct mem_region *m) { while (m) { - if (!m || region_used(m->flags)) + if (!m || is_region_used(m)) return; struct mem_region *n = m->next; - if (!n || region_used(n->flags)) + if (!n || is_region_used(n)) return; m->end = n->end; diff --git a/common/proc.c b/common/proc.c index 8793d00..8824c5a 100644 --- a/common/proc.c +++ b/common/proc.c @@ -29,12 +29,13 @@ stat_t init_proc(void *fdt, struct vm_branch *b) { init_tcbs(); - /* todo: cleanup or something */ - struct tcb *t = new_thread(); + /* TODO: cleanup or something */ + struct tcb *t = create_thread(NULL); if (!t) return ERR_OOMEM; - t->b_r = b; + /* use existing branch */ + t->b_r = b; init_uvmem(t, UVMEM_START, UVMEM_END); /* TODO: this stuff should be placed in __sys_exec */ diff --git a/common/tcb.c b/common/tcb.c index 212e20f..32c31e1 100644 --- a/common/tcb.c +++ b/common/tcb.c @@ -2,6 +2,7 @@ #include <arch/cpu.h> #include <apos/mem.h> #include <apos/pmem.h> +#include <apos/vmem.h> #include <apos/nodes.h> #include <apos/types.h> #include <apos/assert.h> @@ -12,7 +13,6 @@ static id_t start_tid; static size_t num_tids; -static struct node_root root; static struct tcb **tcbs; /* if we ever support systems with massive amounts of cpus, this should probably @@ -31,8 +31,7 @@ void init_tcbs() void destroy_tcbs() { - destroy_nodes(&root); - free_page(MM_O2, (pm_t)tcbs); + free_page(MM_O1, (pm_t)tcbs); } static id_t __alloc_tid(struct tcb *t) @@ -50,10 +49,9 @@ static id_t __alloc_tid(struct tcb *t) return ERR_NF; } -struct tcb *new_thread() +struct tcb *create_thread(struct tcb *p) { - if (unlikely(!tcbs)) - return 0; + hard_assert(tcbs, 0); vm_t bottom = alloc_page(MM_O0, 0); /* move tcb to top of kernel stack, keeping alignment in check @@ -67,20 +65,80 @@ struct tcb *new_thread() tcbs[tid] = t; t->tid = tid; + if (p) { + t->pid = p->pid; + t->proc = p; + } else { + t->pid = t->tid; + } + return t; } -void destroy_thread(struct tcb *t) +static stat_t __clone_proc(struct tcb *p, struct tcb *n) +{ + /* TODO: clone memory regions, and mark them MR_COW, as well as copy + * bm_branch tree but with VM_W off, also at some point write COW + * handler */ + return OK; +} + +struct tcb *create_proc(struct tcb *p) { - if (unlikely(!tcbs)) - return; + hard_assert(tcbs, 0); - /* remove thread id from list */ - tcbs[t->tid] = 0; + /* create a new thread outside the current process */ + struct tcb *n = create_thread(0); + n->b_r = create_vmem(); - /* free associated kernel stack */ + if (likely(p)) + __clone_proc(p, n); /* we have a parent thread */ + else + init_uvmem(n, UVMEM_START, UVMEM_END); + + return n; +} + +static stat_t __destroy_thread_data(struct tcb *t) +{ + /* free vm_branch */ + destroy_vmem(t->b_r); + + /* free associated kernel stack and the structure itself */ vm_t bottom = align_down((vm_t)t, __o_size(MM_O0)); free_page(MM_O0, (pm_t)bottom); + + 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 */ + tcbs[t->tid] = 0; + + /* remove thread from process list */ + if (t->next) + t->next->prev = t->prev; + + if (t->prev) + t->prev->next = t->next; + + return __destroy_thread_data(t); +} + +stat_t destroy_proc(struct tcb *p) +{ + hard_assert(tcbs, ERR_NOINIT); + hard_assert(is_proc(p), ERR_INVAL); + + for (struct tcb *iter = p; (iter = iter->next);) + destroy_thread(iter); + + catastrophic_assert(destroy_uvmem(p)); + return __destroy_thread_data(p); } struct tcb *cur_tcb() @@ -88,6 +146,15 @@ struct tcb *cur_tcb() return cpu_tcb[cpu_id()]; } +struct tcb *cur_proc() +{ + struct tcb *t = cur_tcb(); + if (likely(is_proc(t))) + return t; + else + return t->proc; +} + void use_tcb(struct tcb *t) { cpu_tcb[cpu_id()] = t; @@ -95,18 +162,17 @@ void use_tcb(struct tcb *t) struct tcb *get_tcb(id_t tid) { - if (unlikely(!tcbs)) - return 0; + hard_assert(tcbs, 0); return tcbs[tid]; } stat_t clone_tcb_maps(struct tcb *r) { - hard_assert(r && !r->parent, ERR_INVAL); + hard_assert(r && is_proc(r), ERR_INVAL); struct tcb *t = r; while ((t = t->next)) { - stat_t ret = clone_vmbranch(r->b_r, t->b_r); + stat_t ret = clone_uvmem(r->b_r, t->b_r); if (ret) return ret; } diff --git a/common/uapi/dispatch.c b/common/uapi/dispatch.c index 97fc0d8..5e2e788 100644 --- a/common/uapi/dispatch.c +++ b/common/uapi/dispatch.c @@ -17,7 +17,8 @@ static const sys_t syscall_table[] = { /* ipc */ [SYS_IPC_SERVER] = sys_ipc_server, - [SYS_IPC_REQ] = sys_ipc_req, + [SYS_IPC_REQ_PROC] = sys_ipc_req_proc, + [SYS_IPC_REQ_THREAD] = sys_ipc_req_thread, [SYS_IPC_RESP] = sys_ipc_resp, /* proc */ diff --git a/common/uapi/ipc.c b/common/uapi/ipc.c index d7c9d16..0d2d287 100644 --- a/common/uapi/ipc.c +++ b/common/uapi/ipc.c @@ -11,16 +11,23 @@ SYSCALL_DEFINE1(ipc_server)(sys_arg_t callback) return (struct sys_ret){ OK, 0 }; } -SYSCALL_DEFINE3(ipc_req)(sys_arg_t tid, sys_arg_t d0, sys_arg_t d1) +SYSCALL_DEFINE3(ipc_req_proc)(sys_arg_t pid, sys_arg_t d0, sys_arg_t d1) { - struct tcb *r = get_tcb(tid); - /* something like jump_to_callback(t) */ + struct tcb *r = get_tcb(pid); + /* TODO: something like jump_to_callback(t) */ return (struct sys_ret){ d0, d1 }; } -SYSCALL_DEFINE3(ipc_resp)(sys_arg_t tid, sys_arg_t d0, sys_arg_t d1) +SYSCALL_DEFINE3(ipc_req_thread)(sys_arg_t tid, sys_arg_t d0, sys_arg_t d1) { - struct tcb *r = get_tcb(tid); + struct tcb *t = get_tcb(tid); + /* ditto */ + return (struct sys_ret){ d0, d1 }; +} + +SYSCALL_DEFINE2(ipc_resp)(sys_arg_t d0, sys_arg_t d1) +{ + struct tcb *r = cur_tcb(); /* something like return_from_callback(t, r) */ return (struct sys_ret){ d0, d1 }; } diff --git a/common/vmem.c b/common/vmem.c index ff27ed8..b665491 100644 --- a/common/vmem.c +++ b/common/vmem.c @@ -10,10 +10,33 @@ stat_t init_uvmem(struct tcb *t, vm_t base, vm_t top) return init_region(&t->sp_r, base, top); } +static stat_t __free_mapped_region(struct tcb *t, struct mem_region *m) +{ + stat_t status = OK; + pm_t pa = __addr(m->end - m->start); + if (unmap_freed_region(t->b_r, m->start, pa, m->flags, &status)) + return ERR_MISC; + + return status; +} + +stat_t destroy_uvmem(struct tcb *t) +{ + struct mem_region *m = find_first_region(&t->sp_r); + while (m) { + /* free all memory associated with used regions */ + if (is_region_used(m)) + __free_mapped_region(t, m); + } + + /* destroy region tree itself */ + return destroy_region(&t->sp_r); +} + vm_t alloc_uvmem(struct tcb *t, size_t size, vmflags_t flags) { - /* t exists and is the root tcb of the current process */ - hard_assert(t && !t->parent, ERR_INVAL); + /* t exists and is the process tcb of the current process */ + hard_assert(t && is_proc(t), ERR_INVAL); stat_t status = OK; const vm_t v = alloc_region(&t->sp_r, size, &size, flags); @@ -26,7 +49,7 @@ vm_t alloc_uvmem(struct tcb *t, size_t size, vmflags_t flags) vm_t alloc_fixed_uvmem(struct tcb *t, vm_t start, size_t size, vmflags_t flags) { - hard_assert(t && !t->parent, ERR_INVAL); + hard_assert(t && is_proc(t), ERR_INVAL); stat_t status = OK; const vm_t v = alloc_fixed_region(&t->sp_r, start, size, &size, flags); @@ -41,7 +64,7 @@ vm_t alloc_fixed_uvmem(struct tcb *t, vm_t start, size_t size, vmflags_t flags) /* free_shared_uvmem shouldn't be needed, likely to work with free_uvmem */ vm_t alloc_shared_uvmem(struct tcb *t, size_t size, vmflags_t flags) { - hard_assert(t && t->parent, ERR_INVAL); + hard_assert(t && is_proc(t), ERR_INVAL); stat_t status = OK; const vm_t v = alloc_region(&t->sp_r, size, &size, @@ -86,13 +109,9 @@ stat_t free_uvmem(struct tcb *t, vm_t va) if (!m) return -1; - pm_t pa = __addr(m->end - m->start); - - vmflags_t flags = m->flags; free_region(&t->sp_r, va); - stat_t status = OK; - unmap_freed_region(t->b_r, va, pa, flags, &status); + stat_t status = __free_mapped_region(t, m); if (status == INFO_SEFF) return clone_tcb_maps(t); @@ -107,7 +126,10 @@ stat_t alloc_uvmem_wrapper(struct vm_branch *b, pm_t *offset, vm_t vaddr, return INFO_TRGN; /* try again */ stat_t *status = (stat_t *)data, ret; - ret = *status = map_vpage(b, *offset, vaddr, flags, order); + ret = map_vpage(b, *offset, vaddr, flags, order); + if (status) + *status = ret; + return (ret == INFO_SEFF) ? OK : ret; } @@ -120,7 +142,9 @@ stat_t alloc_shared_wrapper(struct vm_branch *b, pm_t *offset, vm_t vaddr, *offset = alloc_page(MM_O0, *offset); stat_t *status = (stat_t *)data, ret; - ret = *status = map_vpage(b, *offset, vaddr, flags, order); + ret = map_vpage(b, *offset, vaddr, flags, order); + if (status) + *status = ret; return (ret == INFO_SEFF) ? OK : ret; } @@ -137,7 +161,10 @@ stat_t free_uvmem_wrapper(struct vm_branch *b, pm_t *offset, vm_t vaddr, return INFO_TRGN; stat_t *status = (stat_t *)data, ret; - ret = *status = unmap_vpage(b, vaddr); + ret = unmap_vpage(b, vaddr); + if (status) + *status = ret; + /* don't free shared pages, unless they're owned */ if (!__is_set(flags, MR_SHARED) || __is_set(flags, MR_OWNED)) free_page(order, paddr); |
