diff options
| author | Amlal El Mahrouss <amlal.elmahrouss@icloud.com> | 2024-08-31 10:47:14 +0200 |
|---|---|---|
| committer | Amlal El Mahrouss <amlal.elmahrouss@icloud.com> | 2024-08-31 10:47:14 +0200 |
| commit | 2c4b02249ec4355a73b826909ab1889e45871faf (patch) | |
| tree | a904b374c7a738dd3dcb0a580e5667714b72682a /dev/ZKA/Sources/UserProcessScheduler.cxx | |
| parent | d65e85588388bf8c2e0dc8f6b106947110c0e815 (diff) | |
Saving progress on User scheduler implementation.
+ Working on RISC-V, ARM64, POWER64 HALs, to be able to distribute
mulitple versions of the product.
Signed-off-by: Amlal El Mahrouss <amlal.elmahrouss@icloud.com>
Diffstat (limited to 'dev/ZKA/Sources/UserProcessScheduler.cxx')
| -rw-r--r-- | dev/ZKA/Sources/UserProcessScheduler.cxx | 480 |
1 files changed, 480 insertions, 0 deletions
diff --git a/dev/ZKA/Sources/UserProcessScheduler.cxx b/dev/ZKA/Sources/UserProcessScheduler.cxx new file mode 100644 index 00000000..94512913 --- /dev/null +++ b/dev/ZKA/Sources/UserProcessScheduler.cxx @@ -0,0 +1,480 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +/***********************************************************************************/ +/// @file UserProcessScheduler.cxx +/// @brief User UserProcess scheduler. +/***********************************************************************************/ + +#include <KernelKit/UserProcessScheduler.hxx> +#include <KernelKit/PEFDLLInterface.hxx> +#include <KernelKit/MP.hxx> +#include <KernelKit/Heap.hxx> +#include <NewKit/String.hxx> +#include <KernelKit/LPC.hxx> + +///! BUGS: 0 + +/***********************************************************************************/ +/* TODO: Document more the Kernel, sdk and kits. */ +/***********************************************************************************/ + +namespace Kernel +{ + /***********************************************************************************/ + /// @brief Exit Code global variable. + /***********************************************************************************/ + + UInt32 cLastExitCode = 0U; + + /***********************************************************************************/ + /// @brief UserProcess scheduler instance. + /***********************************************************************************/ + + UserProcessScheduler* cProcessScheduler = nullptr; + + /// @brief Gets the last exit code. + /// @note Not thread-safe. + /// @return Int32 the last exit code. + const UInt32& sched_get_exit_code(void) noexcept + { + return cLastExitCode; + } + + /***********************************************************************************/ + /// @brief crash current process. + /***********************************************************************************/ + + void UserProcess::Crash() + { + constexpr auto cUnknownProcess = "?"; + + kcout << (*this->Name == 0 ? cUnknownProcess : this->Name) << ": crashed. (id = " << number(kErrorProcessFault); + kcout << ")\r"; + + this->Status = ProcessStatus::kDead; + + this->Exit(kErrorProcessFault); + } + + /// @brief Gets the local last exit code. + /// @note Not thread-safe. + /// @return Int32 the last exit code. + const UInt32& UserProcess::GetExitCode() noexcept + { + return this->fLastExitCode; + } + + /***********************************************************************************/ + /// @brief Error code variable getter. + /***********************************************************************************/ + + Int32& UserProcess::GetLocalCode() noexcept + { + return fLocalCode; + } + + void UserProcess::Wake(const bool should_wakeup) + { + this->Status = + should_wakeup ? ProcessStatus::kRunning : ProcessStatus::kFrozen; + } + + /***********************************************************************************/ + + VoidPtr UserProcess::New(const SizeT& sz) + { + if (this->HeapCursor) + { + if (this->FreeMemory < 1) + { + ErrLocal() = kErrorHeapOutOfMemory; + + /* We're going out of memory! crash... */ + this->Crash(); + + return nullptr; + } + + this->HeapCursor = reinterpret_cast<VoidPtr>((UIntPtr)this->HeapCursor + (sizeof(sz))); + VoidPtr cursor = this->HeapCursor; + + ++this->UsedMemory; + --this->FreeMemory; + + return cursor; + } + + return nullptr; + } + + /***********************************************************************************/ + + /* @brief checks if runtime pointer is in region. */ + bool rt_is_in_pool(VoidPtr pool_ptr, VoidPtr pool, const SizeT& pool_ptr_cur_sz, const SizeT& pool_ptr_used_sz) + { + if (pool == nullptr || + pool_ptr == nullptr) + return false; + + UIntPtr* uint_pool_ptr = (UIntPtr*)pool_ptr; + UIntPtr* uint_pool = (UIntPtr*)pool; + + return (UIntPtr)&uint_pool > (UIntPtr)&uint_pool_ptr && + pool_ptr_cur_sz > pool_ptr_used_sz; + } + + /* @brief free pointer from usage. */ + Boolean UserProcess::Delete(VoidPtr ptr, const SizeT& sz) + { + if (sz < 1 || this->HeapCursor == this->HeapPtr) + return false; + + // also check for the amount of allocations we've done so far. + if (this->UsedMemory < 1) + return false; + + if (rt_is_in_pool(ptr, this->HeapCursor, this->UsedMemory, this->FreeMemory)) + { + this->HeapCursor = (VoidPtr)((UIntPtr)this->HeapCursor - (sizeof(sz))); + rt_zero_memory(ptr, sz); + + ++this->FreeMemory; + --this->UsedMemory; + + return true; + } + + return false; + } + + /// @brief UserProcess name getter. + const Char* UserProcess::GetProcessName() noexcept + { + return this->Name; + } + + /// @brief UserProcess user getter. + const User* UserProcess::GetOwner() noexcept + { + return this->Owner; + } + + /// @brief UserProcess status getter. + const ProcessStatus& UserProcess::GetStatus() noexcept + { + return this->Status; + } + + /***********************************************************************************/ + + /** + @brief Affinity is the time slot allowed for the process. + */ + const AffinityKind& UserProcess::GetAffinity() noexcept + { + return this->Affinity; + } + + /** + @brief Standard exit proc. + */ + void UserProcess::Exit(const Int32& exit_code) + { + fLastExitCode = exit_code; + cLastExitCode = exit_code; + + //! Delete image if not done already. + if (this->Image) + mm_delete_ke_heap(this->Image); + + if (this->StackFrame) + mm_delete_ke_heap((VoidPtr)this->StackFrame); + + this->Image = nullptr; + this->StackFrame = nullptr; + + if (this->Kind == kDLLKind) + { + Bool success = false; + rtl_fini_shared_object(this, this->DLLPtr, &success); + + if (success) + { + this->DLLPtr = nullptr; + } + } + + if (this->StackReserve) + delete[] this->StackReserve; + + cProcessScheduler->Remove(this->ProcessId); + } + + /// @brief Add process to list. + /// @param process the process *Ref* class. + /// @return the process index inside the team. + SizeT UserProcessScheduler::Add(UserProcess& process) + { + if (!process.Image) + { + return -kErrorInvalidData; + } + + kcout << "UserProcessScheduler: Adding process to team...\r"; + + // Create heap according to type of process. + if (process.Kind == UserProcess::kExeKind) + { + process.HeapPtr = mm_new_ke_heap(process.SizeMemory, true, true); + } + else if (process.Kind == UserProcess::kDLLKind) + { + process.DLLPtr = rtl_init_shared_object(&process); + process.HeapPtr = mm_new_ke_heap(process.SizeMemory, true, true); + } + else + { + // Something went wrong, do not continue, process may be incorrect. + process.Crash(); + return -kErrorProcessFault; + } + + process.StackFrame = reinterpret_cast<HAL::StackFrame*>( + mm_new_ke_heap(sizeof(HAL::StackFrame), Yes, Yes)); + + MUST_PASS(process.StackFrame); + + if (process.Image) + { + // get preferred stack size by app. + const auto cMaxStackSize = process.StackSize; + + process.StackFrame->BP = reinterpret_cast<HAL::Reg>(process.Image); + process.StackFrame->SP = reinterpret_cast<HAL::Reg>(mm_new_ke_heap(cMaxStackSize, Yes, Yes)); + + if (!process.StackFrame->SP) + { + process.StackReserve = new UInt8[cMaxStackSz]; + process.StackFrame->SP = reinterpret_cast<HAL::Reg>(process.StackReserve); + + kcout << "newoskrnl: use fallback reserve.\r"; + } + } + else + { + if (process.Kind != UserProcess::kDLLKind) + { + process.Crash(); + return -kErrorProcessFault; + } + } + + process.Status = ProcessStatus::kStarting; + + process.ProcessId = mTeam.mProcessAmount; + + ++mTeam.mProcessAmount; + + process.HeapCursor = process.HeapPtr; + + mTeam.AsArray()[process.ProcessId] = process; + + kcout << "UserProcessScheduler: Adding process to team [ OK ]...\r"; + + return process.ProcessId; + } + + /***********************************************************************************/ + + UserProcessScheduler& UserProcessScheduler::The() + { + MUST_PASS(cProcessScheduler); + return *cProcessScheduler; + } + + /***********************************************************************************/ + + /// @brief Remove process from list. + /// @param processSlot process slot inside team. + /// @retval true process was removed. + /// @retval false process doesn't exist in team. + Bool UserProcessScheduler::Remove(ProcessID processSlot) + { + // check if process is within range. + if (processSlot > mTeam.AsArray().Count()) + return false; + + // also check if the process isn't a dummy one. + if (mTeam.AsArray()[processSlot].Image == nullptr) + return false; + + kcout << "UserProcessScheduler: Removing process...\r"; + + mTeam.AsArray()[processSlot].Status = ProcessStatus::kDead; + --mTeam.mProcessAmount; + + return true; + } + + /// @brief Run scheduler. + /// @return + SizeT UserProcessScheduler::Run() noexcept + { + SizeT process_index = 0; //! we store this guy to tell the scheduler how many + //! things we have scheduled. + + for (; process_index < mTeam.AsArray().Capacity(); ++process_index) + { + auto& process = mTeam.AsArray()[process_index]; + + //! check if process needs to be scheduled. + if (ProcessHelper::CanBeScheduled(process)) + { + // set the current process. + mTeam.AsRef() = process; + + process.PTime = static_cast<Int32>(process.Affinity); + + kcout << process.Name << ": will be runned.\r"; + + // tell helper to find a core to schedule on. + if (!ProcessHelper::Switch(process.StackFrame, + process.ProcessId)) + process.Crash(); + + continue; + } + else + { + // otherwise increment the P-time. + --process.PTime; + } + } + + return process_index; + } + + /// @brief Gets the current scheduled team. + /// @return + ProcessTeam& UserProcessScheduler::CurrentTeam() + { + return mTeam; + } + + /// @internal + + /// @brief Gets current running process. + /// @return + Ref<UserProcess>& UserProcessScheduler::CurrentProcess() + { + return mTeam.AsRef(); + } + + /// @brief Current proccess id getter. + /// @return UserProcess ID integer. + PID& ProcessHelper::TheCurrentPID() + { + kcout << "ProcessHelper::TheCurrentPID: Leaking ProcessId...\r"; + return cProcessScheduler->CurrentProcess().Leak().ProcessId; + } + + /// @brief Check if process can be schedulded. + /// @param process the process reference. + /// @retval true can be schedulded. + /// @retval false cannot be schedulded. + bool ProcessHelper::CanBeScheduled(UserProcess& process) + { + if (process.Status == ProcessStatus::kFrozen || + process.Status == ProcessStatus::kDead) + return false; + + if (process.Kind == UserProcess::kDLLKind) + { + if (auto start = process.DLLPtr->Load<VoidPtr>(kPefStart, rt_string_len(kPefStart), kPefCode); + start) + { + process.Image = start; + process.StackFrame->BP = reinterpret_cast<HAL::Reg>(start); + } + } + + return process.PTime < 1; + } + + /** + * @brief Scheduler helper class. + */ + + SizeT ProcessHelper::StartScheduling() + { + if (!cProcessScheduler) + { + cProcessScheduler = new UserProcessScheduler(); + MUST_PASS(cProcessScheduler); + + kcout << "newoskrnl: Team capacity: " << number(cProcessScheduler->CurrentTeam().AsArray().Capacity()) << endl; + } + + SizeT ret = cProcessScheduler->Run(); + return ret; + } + + /** + * \brief Does a context switch in a CPU. + * \param the_stack the stackframe of the running app. + * \param new_pid the process's PID. + */ + + bool ProcessHelper::Switch(HAL::StackFrame* the_stack, const PID& new_pid) + { + if (!the_stack || new_pid < 0) + return false; + + kcout << "newoskrnl: Finding hardware thread...\r"; + + for (SizeT index = 0UL; index < HardwareThreadScheduler::The().Count(); ++index) + { + if (HardwareThreadScheduler::The()[index].Leak()->Kind() == kInvalidHart) + continue; + + if (HardwareThreadScheduler::The()[index].Leak()->IsBusy()) + continue; + + if (HardwareThreadScheduler::The()[index].Leak()->Kind() != + ThreadKind::kHartBoot && + HardwareThreadScheduler::The()[index].Leak()->Kind() != + ThreadKind::kHartSystemReserved) + { + HardwareThreadScheduler::The()[index].Leak()->Busy(true); + + ProcessHelper::TheCurrentPID() = new_pid; + + kcout << "newoskrnl: Found hardware thread...\r"; + + bool ret = HardwareThreadScheduler::The()[index].Leak()->Switch(the_stack); + + HardwareThreadScheduler::The()[index].Leak()->Busy(false); + + return ret; + } + } + + return false; + } + + /// @brief this checks if any process is on the team. + UserProcessScheduler::operator bool() + { + return mTeam.AsArray().Count() > 0; + } + + /// @brief this checks if no process is on the team. + bool UserProcessScheduler::operator!() + { + return mTeam.AsArray().Count() == 0; + } +} // namespace Kernel |
