diff options
| author | Kimplul <kimi.h.kuparinen@gmail.com> | 2024-07-09 17:35:56 +0300 |
|---|---|---|
| committer | Kimplul <kimi.h.kuparinen@gmail.com> | 2024-07-09 17:35:56 +0300 |
| commit | 298636079d912d0936f8156a609fe74b839c547b (patch) | |
| tree | e0c22ce0e7b7c8a29e3937616076e8fb327fde8b /src/tcb.c | |
| parent | e134202611a50b358c147c92bfb8a7f443030b8b (diff) | |
| download | kmi-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.c | 36 |
1 files changed, 29 insertions, 7 deletions
@@ -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 */ |
