#include <lunaix/mm/mmap.h>
#include <lunaix/mm/page.h>
#include <lunaix/syslog.h>
+#include <lunaix/kpreempt.h>
#include <usr/lunaix/threads.h>
-#include <sys/abi.h>
-#include <sys/mm/mm_defs.h>
+#include <asm/abi.h>
+#include <asm/mm_defs.h>
LOG_MODULE("THREAD")
static ptr_t
__alloc_kernel_thread_stack(struct proc_info* proc, ptr_t vm_mnt)
{
- pfn_t kstack_top = leaf_count(KSTACK_AREA_END);
+ pfn_t kstack_top = pfn(KSTACK_AREA_END);
pfn_t kstack_end = pfn(KSTACK_AREA);
pte_t* ptep = mkptep_pn(vm_mnt, kstack_top);
while (ptep_pfn(ptep) > kstack_end) {
- ptep -= KSTACK_PAGES + 1;
+ ptep -= KSTACK_PAGES;
- pte_t pte = pte_at(ptep + 1);
+ pte_t pte = pte_at(ptep);
if (pte_isnull(pte)) {
goto found;
}
+
+ ptep--;
}
WARN("failed to create kernel stack: max stack num reach\n");
return 0;
}
- set_pte(ptep, guard_pte);
- ptep_map_leaflet(ptep + 1, mkpte_prot(KERNEL_DATA), leaflet);
+ set_pte(ptep++, guard_pte);
+ ptep_map_leaflet(ptep, mkpte_prot(KERNEL_DATA), leaflet);
ptep += KSTACK_PAGES;
return align_stack(ptep_va(ptep, LFT_SIZE) - 1);
}
+static int
+__thread_putsleep(int seconds)
+{
+ if (!seconds) {
+ return 0;
+ }
+
+ struct scheduler* sched;
+ time_t systime;
+ struct haybed* bed;
+
+ sched = scheduler();
+ systime = clock_systime() / 1000;
+ bed = ¤t_thread->sleep;
+
+ if (bed->wakeup_time) {
+ return (bed->wakeup_time - systime);
+ }
+
+ bed->wakeup_time = systime + seconds;
+
+ if (llist_empty(&bed->sleepers)) {
+ llist_append(&sched->sleepers, &bed->sleepers);
+ }
+
+ block_current_thread();
+ return seconds;
+}
+
void
thread_release_mem(struct thread* thread)
{
pte_t* ptep = mkptep_va(vm_mnt, thread->kstack);
leaflet = pte_leaflet(*ptep);
- ptep -= KSTACK_PAGES - 1;
+ ptep -= KSTACK_PAGES;
set_pte(ptep, null_pte);
ptep_unmap_leaflet(ptep + 1, leaflet);
return NULL;
}
+void
+thread_stats_update(bool inbound, bool voluntary)
+{
+ struct thread_stats* stats;
+ time_t now;
+
+ now = clock_systime();
+ stats = ¤t_thread->stats;
+
+ stats->at_user = !kernel_context(current_thread->hstate);
+
+ if (!inbound) {
+ if (kernel_process(current_thread->process) ||
+ stats->at_user)
+ {
+ // exiting to user or kernel (kernel thread only), how graceful
+ stats->last_leave = now;
+ }
+ else {
+ // exiting to kernel, effectively reentry
+ stats->last_reentry = now;
+ }
+
+ stats->last_resume = now;
+ return;
+ }
+
+ stats->last_reentry = now;
+
+ if (!stats->at_user)
+ {
+ // entering from kernel, it is a kernel preempt
+ thread_stats_update_kpreempt();
+ return;
+ }
+
+ // entering from user space, a clean entrance.
+
+ if (!voluntary) {
+ stats->entry_count_invol++;
+ }
+ else {
+ stats->entry_count_vol++;
+ }
+
+ thread_stats_reset_kpreempt();
+ stats->last_entry = now;
+}
+
+void
+kthread_spawn(ptr_t entry)
+{
+ assert(kernel_process(__current));
+
+ struct thread* th = create_thread(__current, false);
+
+ assert(th);
+ start_thread(th, entry);
+ detach_thread(th);
+}
+
+void
+kthread_sleep(int seconds)
+{
+ if (__thread_putsleep(seconds))
+ yield_current();
+}
+
__DEFINE_LXSYSCALL3(int, th_create, tid_t*, tid,
struct uthread_param*, thparam, void*, entry)
{
+ no_preemption();
+
struct thread* th = create_thread(__current, true);
if (!th) {
return EAGAIN;
}
while (!proc_terminated(th)) {
- sched_pass();
+ yield_current();
}
if (val_ptr) {
*val_ptr = (void*)th->exit_val;
}
+ no_preemption();
destory_thread(th);
return 0;
return 0;
}
+
+__DEFINE_LXSYSCALL1(unsigned int, sleep, unsigned int, seconds)
+{
+ int sec;
+
+ sec = __thread_putsleep(seconds);
+ store_retval(seconds);
+
+ if (sec)
+ schedule();
+
+ return 0;
+}
\ No newline at end of file