summaryrefslogtreecommitdiffhomepage
path: root/dev/zka/src/UserProcessScheduler.cxx
diff options
context:
space:
mode:
authorAmlal <amlal@el-mahrouss-logic.com>2024-09-22 17:46:11 +0200
committerAmlal <amlal@el-mahrouss-logic.com>2024-09-22 17:46:11 +0200
commit8719b4570a2d10dd49a0d3a47e24f5c55bdda85e (patch)
treeba095740888f3768e08b2ea058b0ea6da2d0403d /dev/zka/src/UserProcessScheduler.cxx
parent45944b3d2dab04b763fcc6d10164fe8069e60b08 (diff)
:boom: A big refactor on the filesystem structure.
Signed-off-by: Amlal <amlal@el-mahrouss-logic.com>
Diffstat (limited to 'dev/zka/src/UserProcessScheduler.cxx')
-rw-r--r--dev/zka/src/UserProcessScheduler.cxx484
1 files changed, 484 insertions, 0 deletions
diff --git a/dev/zka/src/UserProcessScheduler.cxx b/dev/zka/src/UserProcessScheduler.cxx
new file mode 100644
index 00000000..88980f8d
--- /dev/null
+++ b/dev/zka/src/UserProcessScheduler.cxx
@@ -0,0 +1,484 @@
+/* -------------------------------------------
+
+ Copyright ZKA Technologies.
+
+ FILE: UserProcessScheduler.cxx
+ PURPOSE: Low Exception Process scheduler.
+
+------------------------------------------- */
+
+/***********************************************************************************/
+/// @file UserProcessScheduler.cxx
+/// @brief User Process scheduler.
+/***********************************************************************************/
+
+#include <KernelKit/UserProcessScheduler.hxx>
+#include <KernelKit/IPEFDLLObject.hxx>
+#include <KernelKit/HardwareThreadScheduler.hxx>
+#include <KernelKit/Heap.hxx>
+#include <NewKit/String.hxx>
+#include <KernelKit/LPC.hxx>
+
+///! BUGS: 0
+
+/***********************************************************************************/
+/** TODO: Document the Kernel, SDK and kits. */
+/***********************************************************************************/
+
+namespace Kernel
+{
+ /***********************************************************************************/
+ /// @brief Exit Code global variable.
+ /***********************************************************************************/
+
+ STATIC UInt32 cLastExitCode = 0U;
+
+ /***********************************************************************************/
+ /// @brief User Process scheduler global object.
+ /***********************************************************************************/
+
+ 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()
+ {
+ if (*this->Name != 0)
+ kcout << this->Name << ": crashed, error id: " << number(kErrorProcessFault) << endl;
+
+ 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 ? ProcessStatusKind::kRunning : ProcessStatusKind::kFrozen;
+ }
+
+ /***********************************************************************************/
+
+ /** @brief Add pointer to entry. */
+ VoidPtr UserProcess::New(const SizeT& sz)
+ {
+#ifdef __ZKA_AMD64__
+ auto pd = hal_read_cr3();
+ hal_write_cr3(reinterpret_cast<VoidPtr>(this->MemoryPD));
+
+ auto ptr = mm_new_heap(sz, Yes, Yes);
+
+ hal_write_cr3(reinterpret_cast<VoidPtr>(pd));
+#else
+ auto ptr = mm_new_heap(sz, Yes, Yes);
+#endif
+
+ if (!this->MemoryEntryList)
+ {
+ this->MemoryEntryList = new UserProcess::PROCESS_MEMORY_ENTRY();
+ this->MemoryEntryList->MemoryEntry = ptr;
+
+ this->MemoryEntryList->MemoryPrev = nullptr;
+ this->MemoryEntryList->MemoryNext = nullptr;
+
+ return ptr;
+ }
+ else
+ {
+ auto entry = this->MemoryEntryList;
+ PROCESS_MEMORY_ENTRY* prev_entry = nullptr;
+
+ while (!entry)
+ {
+ prev_entry = entry;
+ entry = entry->MemoryNext;
+ }
+
+ entry->MemoryNext = new UserProcess::PROCESS_MEMORY_ENTRY();
+ entry->MemoryNext->MemoryEntry = ptr;
+
+ entry->MemoryNext->MemoryPrev = entry;
+ entry->MemoryNext->MemoryNext = nullptr;
+ }
+
+ return nullptr;
+ }
+
+ /***********************************************************************************/
+
+ /** @brief Free pointer from usage. */
+ Boolean UserProcess::Delete(VoidPtr ptr, const SizeT& sz)
+ {
+ auto entry = this->MemoryEntryList;
+
+ while (entry)
+ {
+ if (entry->MemoryEntry == ptr)
+ {
+#ifdef __ZKA_AMD64__
+ auto pd = hal_read_cr3();
+ hal_write_cr3(reinterpret_cast<VoidPtr>(this->MemoryPD));
+
+ Bool ret = mm_delete_heap(ptr);
+ hal_write_cr3(reinterpret_cast<VoidPtr>(pd));
+
+ return ret;
+#else
+ bool ret = mm_delete_heap(ptr);
+ return ret;
+#endif
+ }
+
+ entry = entry->MemoryNext;
+ }
+
+ 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 ProcessStatusKind& 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)
+ {
+ this->Status = ProcessStatusKind::kDead;
+
+ fLastExitCode = exit_code;
+ cLastExitCode = exit_code;
+
+ //! Delete image if not done already.
+ if (this->Image && mm_is_valid_heap(this->Image))
+ mm_delete_heap(this->Image);
+
+ if (this->StackFrame && mm_is_valid_heap(this->StackFrame))
+ mm_delete_heap((VoidPtr)this->StackFrame);
+
+ this->Image = nullptr;
+ this->StackFrame = nullptr;
+
+ if (this->Kind == kDLLKind)
+ {
+ Bool success = false;
+ rtl_fini_dll(this, this->DLLPtr, &success);
+
+ if (success)
+ {
+ this->DLLPtr = nullptr;
+ }
+ }
+
+ if (this->StackReserve)
+ delete[] this->StackReserve;
+
+ this->ProcessId = 0;
+
+ if (this->ProcessId > 0)
+ UserProcessScheduler::The().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 (mTeam.mProcessAmount > kSchedProcessLimitPerTeam)
+ return 0;
+
+#ifdef __ZKA_AMD64__
+ process.MemoryPD = reinterpret_cast<UIntPtr>(hal_read_cr3());
+#endif // __ZKA_AMD64__
+
+ process.Status = ProcessStatusKind::kStarting;
+
+ process.StackFrame = (HAL::StackFramePtr)mm_new_heap(sizeof(HAL::StackFrame), Yes, Yes);
+
+ if (!process.StackFrame)
+ {
+ process.Crash();
+ return -kErrorProcessFault;
+ }
+
+ // Create heap according to type of process.
+ if (process.Kind == UserProcess::kDLLKind)
+ {
+ process.DLLPtr = rtl_init_dll(&process);
+ }
+
+ if (!process.Image)
+ {
+ if (process.Kind != UserProcess::kDLLKind)
+ {
+ process.Crash();
+ return -kErrorProcessFault;
+ }
+ }
+
+ // get preferred stack size by app.
+ const auto cMaxStackSize = process.StackSize;
+ process.StackReserve = (UInt8*)mm_new_heap(sizeof(UInt8) * cMaxStackSize, Yes, Yes);
+
+ if (!process.StackReserve)
+ {
+ mm_delete_heap(process.StackFrame);
+ process.StackFrame = nullptr;
+ return -kErrorProcessFault;
+ }
+
+ ++mTeam.mProcessAmount;
+
+ process.ProcessId = mTeam.mProcessAmount;
+ process.Status = ProcessStatusKind::kRunning;
+
+ // avoid the pitfalls of moving process.
+ auto ret_pid = process.ProcessId;
+
+ mTeam.AsArray()[process.ProcessId] = move(process);
+
+ return ret_pid;
+ }
+
+ /***********************************************************************************/
+
+ UserProcessScheduler& UserProcessScheduler::The()
+ {
+ MUST_PASS(cProcessScheduler);
+ return *cProcessScheduler;
+ }
+
+ /***********************************************************************************/
+
+ /// @brief Remove process from list.
+ /// @param process_id process slot inside team.
+ /// @retval true process was removed.
+ /// @retval false process doesn't exist in team.
+
+ /***********************************************************************************/
+
+ Bool UserProcessScheduler::Remove(ProcessID process_id)
+ {
+ // check if process is within range.
+ if (process_id > mTeam.AsArray().Count())
+ return false;
+
+ mTeam.AsArray()[process_id].Status = ProcessStatusKind::kDead;
+ --mTeam.mProcessAmount;
+
+ return true;
+ }
+
+ /***********************************************************************************/
+
+ /// @brief Run User scheduler object.
+ /// @return Process executed within team.
+
+ /***********************************************************************************/
+
+ 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)
+ {
+ kcout << "Grabbing available process in team...\r";
+
+ auto& process = mTeam.AsArray()[process_index];
+
+ //! check if process needs to be scheduled.
+ if (UserProcessHelper::CanBeScheduled(process))
+ {
+ kcout << process.Name << ": will be runned.\r";
+
+ // Set current process header.
+ this->CurrentProcess() = process;
+
+ process.PTime = static_cast<Int32>(process.Affinity);
+
+ // tell helper to find a core to schedule on.
+ if (!UserProcessHelper::Switch(process.Image, &process.StackReserve[process.StackSize - 1], process.StackFrame,
+ process.ProcessId))
+ {
+ process.Crash();
+ continue;
+ }
+ }
+ }
+
+ kcout << "Scheduled Process Count: " << number(process_index) << endl;
+
+ return process_index;
+ }
+
+ /// @brief Gets the current scheduled team.
+ /// @return
+ UserProcessTeam& 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& UserProcessHelper::TheCurrentPID()
+ {
+ kcout << "UserProcessHelper::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 UserProcessHelper::CanBeScheduled(const UserProcess& process)
+ {
+ kcout << "Checking process status...\r";
+
+ if (process.Status == ProcessStatusKind::kFrozen ||
+ process.Status == ProcessStatusKind::kDead)
+ return No;
+
+ if (!process.Image &&
+ process.Kind == UserProcess::kExeKind)
+ return No;
+
+ return Yes;
+ }
+
+ /**
+ * @brief Scheduler helper class.
+ */
+
+ EXTERN
+ HardwareThreadScheduler* cHardwareThreadScheduler;
+
+ SizeT UserProcessHelper::StartScheduling()
+ {
+ if (!cHardwareThreadScheduler)
+ {
+ cHardwareThreadScheduler = mm_new_class<HardwareThreadScheduler>();
+ MUST_PASS(cHardwareThreadScheduler);
+ }
+
+ if (!cProcessScheduler)
+ {
+ cProcessScheduler = mm_new_class<UserProcessScheduler>();
+ MUST_PASS(cProcessScheduler);
+ }
+
+ 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 UserProcessHelper::Switch(VoidPtr image_ptr, UInt8* stack, HAL::StackFramePtr frame_ptr, const PID& new_pid)
+ {
+ if (!stack || !frame_ptr || !image_ptr || new_pid < 0)
+ return No;
+
+ for (SizeT index = 0UL; index < HardwareThreadScheduler::The().Count(); ++index)
+ {
+ if (HardwareThreadScheduler::The()[index].Leak()->Kind() == kInvalidHart)
+ continue;
+
+ if (HardwareThreadScheduler::The()[index].Leak()->Kind() !=
+ ThreadKind::kHartBoot &&
+ HardwareThreadScheduler::The()[index].Leak()->Kind() !=
+ ThreadKind::kHartSystemReserved)
+ {
+ PID prev_pid = UserProcessHelper::TheCurrentPID();
+ UserProcessHelper::TheCurrentPID() = new_pid;
+
+ auto prev_ptime = HardwareThreadScheduler::The()[index].Leak()->fPTime;
+ HardwareThreadScheduler::The()[index].Leak()->fPTime = UserProcessScheduler::The().CurrentTeam().AsArray()[new_pid].ProcessId;
+ Bool ret = HardwareThreadScheduler::The()[index].Leak()->Switch(image_ptr, stack, frame_ptr);
+
+ if (!ret)
+ {
+ HardwareThreadScheduler::The()[index].Leak()->fPTime = prev_ptime;
+ UserProcessHelper::TheCurrentPID() = prev_pid;
+
+ continue;
+ }
+ }
+ }
+
+ 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