diff --git a/usr/testbed/test.cpp b/usr/testbed/test.cpp index ef3f2eb..3f7f324 100644 --- a/usr/testbed/test.cpp +++ b/usr/testbed/test.cpp @@ -1,7 +1,10 @@ #include +#include uint64_t main(uint64_t init_port_cap) { dbgln("testbed"); + check(ZThreadSleep(2000)); + dbgln("testbed2"); return glcr::OK; } diff --git a/zion/include/zcall.h b/zion/include/zcall.h index efe5d16..c5f9ca6 100644 --- a/zion/include/zcall.h +++ b/zion/include/zcall.h @@ -17,6 +17,7 @@ SYS4(ThreadStart, z_cap_t, thread_cap, uint64_t, entry, uint64_t, arg1, uint64_t, arg2); SYS0(ThreadExit); SYS1(ThreadWait, z_cap_t, thread_cap); +SYS1(ThreadSleep, uint64_t, millis); SYS5(AddressSpaceMap, z_cap_t, vmas_cap, uint64_t, vmas_offset, z_cap_t, vmmo_cap, uint64_t, align, uint64_t*, vaddr); diff --git a/zion/include/ztypes.h b/zion/include/ztypes.h index f25df71..490e0d7 100644 --- a/zion/include/ztypes.h +++ b/zion/include/ztypes.h @@ -19,6 +19,7 @@ const uint64_t kZionThreadCreate = 0x10; const uint64_t kZionThreadStart = 0x11; const uint64_t kZionThreadExit = 0x12; const uint64_t kZionThreadWait = 0x13; +const uint64_t kZionThreadSleep = 0x14; // Memory Calls const uint64_t kZionAddressSpaceMap = 0x21; diff --git a/zion/object/thread.h b/zion/object/thread.h index 53bee2b..6c32007 100644 --- a/zion/object/thread.h +++ b/zion/object/thread.h @@ -29,6 +29,7 @@ class Thread : public KernelObject, public glcr::IntrusiveListNode { RUNNING, RUNNABLE, BLOCKED, + SLEEPING, CLEANUP, FINISHED, }; @@ -69,6 +70,9 @@ class Thread : public KernelObject, public glcr::IntrusiveListNode { void Wait(); + void SetSleepTicks(uint64_t sleep_ticks) { sleep_ticks_ = sleep_ticks; } + bool DecrementSleepTicks() { return --sleep_ticks_ == 0; } + private: friend class glcr::MakeRefCountedFriend; Thread(Process& proc, uint64_t tid); @@ -79,6 +83,7 @@ class Thread : public KernelObject, public glcr::IntrusiveListNode { State state_ = CREATED; bool is_kernel_ = false; uint64_t user_stack_base_; + uint64_t sleep_ticks_; // Startup Context for the thread. uint64_t rip_; diff --git a/zion/scheduler/scheduler.cpp b/zion/scheduler/scheduler.cpp index 5d745c8..2a21d30 100644 --- a/zion/scheduler/scheduler.cpp +++ b/zion/scheduler/scheduler.cpp @@ -45,14 +45,11 @@ void Scheduler::Preempt() { return; } + DecrementSleepingThreads(); + ClearDeadThreadsFromFront(); asm volatile("cli"); - if (current_thread_ == sleep_thread_) { - // Sleep should never be preempted. (We should yield it if another thread - // becomes scheduleable). - return; - } if (runnable_threads_.size() == 0) { // Continue. @@ -102,9 +99,33 @@ void Scheduler::Yield() { SwapToCurrent(*prev); } +void Scheduler::Sleep(uint64_t millis) { + // FIXME: Improve resolution of sleep calls. + uint64_t ticks = (millis / 50) + 1; + current_thread_->SetSleepTicks(ticks); + current_thread_->SetState(Thread::SLEEPING); + sleeping_threads_.PushBack(current_thread_); + Yield(); +} + void Scheduler::ClearDeadThreadsFromFront() { while (runnable_threads_.size() > 0 && runnable_threads_.PeekFront()->IsDying()) { runnable_threads_.PopFront(); } } + +void Scheduler::DecrementSleepingThreads() { + auto thread = sleeping_threads_.PeekFront(); + while (thread) { + if (thread->DecrementSleepTicks()) { + auto thread_next = thread->next_; + sleeping_threads_.Remove(thread); + thread->SetState(Thread::RUNNABLE); + runnable_threads_.PushBack(thread); + thread = thread_next; + } else { + thread = thread->next_; + } + } +} diff --git a/zion/scheduler/scheduler.h b/zion/scheduler/scheduler.h index 823ded8..37aa0b9 100644 --- a/zion/scheduler/scheduler.h +++ b/zion/scheduler/scheduler.h @@ -23,18 +23,23 @@ class Scheduler { void Preempt(); void Yield(); + void Sleep(uint64_t millis); + private: bool enabled_ = false; glcr::RefPtr current_thread_; glcr::IntrusiveList runnable_threads_; + glcr::IntrusiveList sleeping_threads_; + glcr::RefPtr sleep_thread_; Scheduler(); void SwapToCurrent(Thread& prev); void ClearDeadThreadsFromFront(); + void DecrementSleepingThreads(); }; extern Scheduler* gScheduler; diff --git a/zion/syscall/syscall.cpp b/zion/syscall/syscall.cpp index ac260a5..70e9677 100644 --- a/zion/syscall/syscall.cpp +++ b/zion/syscall/syscall.cpp @@ -59,6 +59,7 @@ extern "C" z_err_t SyscallHandler(uint64_t call_id, void* req) { CASE(ThreadStart); CASE(ThreadExit); CASE(ThreadWait); + CASE(ThreadSleep); // syscall/address_space.h CASE(AddressSpaceMap); CASE(AddressSpaceUnmap); diff --git a/zion/syscall/thread.cpp b/zion/syscall/thread.cpp index 36ca2fe..19f212e 100644 --- a/zion/syscall/thread.cpp +++ b/zion/syscall/thread.cpp @@ -53,3 +53,8 @@ glcr::ErrorCode ThreadWait(ZThreadWaitReq* req) { thread->Wait(); return glcr::OK; } + +glcr::ErrorCode ThreadSleep(ZThreadSleepReq* req) { + gScheduler->Sleep(req->millis); + return glcr::OK; +} diff --git a/zion/syscall/thread.h b/zion/syscall/thread.h index 17cc288..4abd323 100644 --- a/zion/syscall/thread.h +++ b/zion/syscall/thread.h @@ -8,3 +8,4 @@ glcr::ErrorCode ThreadCreate(ZThreadCreateReq* req); glcr::ErrorCode ThreadStart(ZThreadStartReq* req); glcr::ErrorCode ThreadExit(ZThreadExitReq*); glcr::ErrorCode ThreadWait(ZThreadWaitReq* req); +glcr::ErrorCode ThreadSleep(ZThreadSleepReq* req);