aboutsummaryrefslogtreecommitdiff
path: root/src/tcb.c
diff options
context:
space:
mode:
authorKimplul <kimi.h.kuparinen@gmail.com>2024-07-09 17:35:56 +0300
committerKimplul <kimi.h.kuparinen@gmail.com>2024-07-09 17:35:56 +0300
commit298636079d912d0936f8156a609fe74b839c547b (patch)
treee0c22ce0e7b7c8a29e3937616076e8fb327fde8b /src/tcb.c
parente134202611a50b358c147c92bfb8a7f443030b8b (diff)
downloadkmi-298636079d912d0936f8156a609fe74b839c547b.tar.gz
kmi-298636079d912d0936f8156a609fe74b839c547b.zip
allow mapping null page
+ User has to 'free' the 0 page before it becomes accessible to mapping. Probably worth noting that this is likely VERY niche and mainly concerns stuff like certain kinds of emulators that I'm still eons from implementing, but still. Unbacked pages can also be useful for some kinds of notifications, like 'if someone writes to this page, please report it to me with this ID' or whatever, I remember seeing some discussion about it somewhere but that's also not really relevant for the moment. Most significantly, at least with the current design, after the null page is freed it becomes available for use to regular req_mem() calls, so users should probably using locks around memory requests. That's probably a good idea anyway as internally the kernal has to lock the virtual memory, and without a scheduler it might cause threads to spin for a while in the kernel which is rather bad.
Diffstat (limited to 'src/tcb.c')
-rw-r--r--src/tcb.c36
1 files changed, 29 insertions, 7 deletions
diff --git a/src/tcb.c b/src/tcb.c
index 053ea6f..48f1d3b 100644
--- a/src/tcb.c
+++ b/src/tcb.c
@@ -123,11 +123,14 @@ struct tcb *create_thread(struct tcb *p)
assert(tcbs);
vm_t bottom = alloc_page(KERNEL_STACK_PAGE_ORDER);
+ if (!bottom)
+ return NULL;
+
/* move tcb to top of kernel stack, keeping alignment in check
* (hopefully) */
/** \todo check alignment */
- bottom = bottom + order_size(MM_O0) - sizeof(struct tcb);
- struct tcb *t = (struct tcb *)align_down(bottom, sizeof(long));
+ vm_t top = bottom + order_size(MM_O0) - sizeof(struct tcb);
+ struct tcb *t = (struct tcb *)align_down(top, sizeof(long));
memset(t, 0, sizeof(struct tcb));
id_t tid = __alloc_tid(t);
@@ -141,9 +144,19 @@ struct tcb *create_thread(struct tcb *p)
* 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 {
- t->proc.vmem = create_vmem();
- init_uvmem(t, UVMEM_START, UVMEM_END);
+ }
+ else {
+ if (!(t->proc.vmem = create_vmem())) {
+ free_page(MM_O0, bottom);
+ return NULL;
+ }
+
+ if (init_uvmem(t)) {
+ destroy_vmem(t->proc.vmem);
+ free_page(MM_O0, bottom);
+ return NULL;
+ }
+
t->pid = t->tid;
t->rid = t->tid;
p = t;
@@ -151,7 +164,16 @@ struct tcb *create_thread(struct tcb *p)
t->eid = t->pid;
t->rid = p->rid;
- t->rpc.vmem = create_vmem();
+
+ if (!(t->rpc.vmem = create_vmem())) {
+ if (likely(p))
+ return NULL;
+
+ destroy_vmem(t->proc.vmem);
+ free_page(MM_O0, bottom);
+ return NULL;
+ }
+
setup_rpc_stack(t);
reference_proc(p);
@@ -191,7 +213,7 @@ struct tcb *create_proc(struct tcb *p)
/* create a new thread outside the current process */
struct tcb *n = create_thread(NULL);
if (!n)
- return 0;
+ return NULL;
if (p)
__copy_proc(p, n); /* we have a parent process i.e. fork */