1 #include <lunaix/process.h>
2 #include <lunaix/sched.h>
3 #include <lunaix/syscall.h>
4 #include <lunaix/syscall_utils.h>
5 #include <lunaix/mm/mmap.h>
6 #include <lunaix/mm/page.h>
7 #include <lunaix/syslog.h>
9 #include <usr/lunaix/threads.h>
12 #include <sys/mm/mm_defs.h>
17 __alloc_user_thread_stack(struct proc_info* proc, struct mm_region** stack_region, ptr_t vm_mnt)
19 ptr_t th_stack_top = (proc->thread_count + 1) * USR_STACK_SIZE;
20 th_stack_top = ROUNDUP(USR_STACK_END - th_stack_top, MEM_PAGE);
22 struct mm_region* vmr;
23 struct proc_mm* mm = vmspace(proc);
24 struct mmap_param param = { .vms_mnt = vm_mnt,
26 .mlen = USR_STACK_SIZE,
27 .proct = PROT_READ | PROT_WRITE,
28 .flags = MAP_ANON | MAP_PRIVATE,
29 .type = REGION_TYPE_STACK };
31 int errno = mmap_user((void**)&th_stack_top, &vmr, th_stack_top, NULL, ¶m);
34 WARN("failed to create user thread stack: %d", errno);
38 set_pte(mkptep_va(vm_mnt, vmr->start), guard_pte);
42 ptr_t stack_top = align_stack(th_stack_top + USR_STACK_SIZE - 1);
47 __alloc_kernel_thread_stack(struct proc_info* proc, ptr_t vm_mnt)
49 pfn_t kstack_top = leaf_count(KSTACK_AREA_END);
50 pfn_t kstack_end = pfn(KSTACK_AREA);
51 pte_t* ptep = mkptep_pn(vm_mnt, kstack_top);
52 while (ptep_pfn(ptep) > kstack_end) {
55 // first page in the kernel stack is guardian page
56 pte_t pte = *(ptep + 1);
57 if (pte_isnull(pte)) {
62 WARN("failed to create kernel stack: max stack num reach\n");
66 // KSTACK_PAGES = 3, removal one guardian pte, give order 1 page
67 struct leaflet* leaflet = alloc_leaflet(1);
70 WARN("failed to create kernel stack: nomem\n");
74 set_pte(ptep, guard_pte);
75 ptep_map_leaflet(ptep + 1, mkpte_prot(KERNEL_DATA), leaflet);
78 return align_stack(ptep_va(ptep, LFT_SIZE) - 1);
82 thread_release_mem(struct thread* thread)
84 struct leaflet* leaflet;
85 struct proc_mm* mm = vmspace(thread->process);
86 ptr_t vm_mnt = mm->vm_mnt;
88 // Ensure we have mounted
91 pte_t* ptep = mkptep_va(vm_mnt, thread->kstack);
92 leaflet = pte_leaflet(*ptep);
94 ptep -= KSTACK_PAGES - 1;
95 set_pte(ptep, null_pte);
96 ptep_unmap_leaflet(ptep + 1, leaflet);
98 leaflet_return(leaflet);
100 if (thread->ustack) {
101 if ((thread->ustack->start & 0xfff)) {
102 fail("invalid ustack struct");
104 mem_unmap_region(vm_mnt, thread->ustack);
109 create_thread(struct proc_info* proc, bool with_ustack)
111 struct proc_mm* mm = vmspace(proc);
114 ptr_t vm_mnt = mm->vm_mnt;
115 struct mm_region* ustack_region = NULL;
117 !(__alloc_user_thread_stack(proc, &ustack_region, vm_mnt)))
122 ptr_t kstack = __alloc_kernel_thread_stack(proc, vm_mnt);
124 mem_unmap_region(vm_mnt, ustack_region);
128 struct thread* th = alloc_thread(proc);
134 th->ustack = ustack_region;
140 start_thread(struct thread* th, ptr_t entry)
143 struct proc_mm* mm = vmspace(th->process);
147 struct transfer_context transfer;
148 if (!kernel_addr(entry)) {
151 ptr_t ustack_top = align_stack(th->ustack->end - 1);
152 ustack_top -= 16; // pre_allocate a 16 byte for inject parameter
153 thread_create_user_transfer(&transfer, th->kstack, ustack_top, entry);
155 th->ustack_top = ustack_top;
158 thread_create_kernel_transfer(&transfer, th->kstack, entry);
161 inject_transfer_context(mm->vm_mnt, &transfer);
162 th->intr_ctx = (isr_param*)transfer.inject;
168 exit_thread(void* val) {
169 terminate_current_thread((ptr_t)val);
174 thread_find(struct proc_info* proc, tid_t tid)
176 struct thread *pos, *n;
177 llist_for_each(pos, n, &proc->threads, proc_sibs) {
178 if (pos->tid == tid) {
186 __DEFINE_LXSYSCALL4(int, th_create, tid_t*, tid, struct uthread_info*, thinfo,
187 void*, entry, void*, param)
189 struct thread* th = create_thread(__current, true);
194 start_thread(th, (ptr_t)entry);
196 ptr_t ustack_top = th->ustack_top;
197 *((void**)ustack_top) = param;
199 thinfo->th_stack_sz = region_size(th->ustack);
200 thinfo->th_stack_top = (void*)ustack_top;
209 __DEFINE_LXSYSCALL(tid_t, th_self)
211 return current_thread->tid;
214 __DEFINE_LXSYSCALL1(void, th_exit, void*, val)
219 __DEFINE_LXSYSCALL2(int, th_join, tid_t, tid, void**, val_ptr)
221 struct thread* th = thread_find(__current, tid);
226 if (th == current_thread) {
230 while (!proc_terminated(th)) {
235 *val_ptr = (void*)th->exit_val;
243 __DEFINE_LXSYSCALL1(int, th_detach, tid_t, tid)
245 // can not detach the only thread
246 if (__current->thread_count == 1) {
250 struct thread* th = thread_find(__current, tid);
259 __DEFINE_LXSYSCALL2(int, th_kill, tid_t, tid, int, signum)
261 struct thread* target = thread_find(__current, tid);
266 if (signum > _SIG_NUM) {
271 thread_setsignal(target, signum);