summaryrefslogtreecommitdiffhomepage
path: root/Kernel/Source/ProcessScheduler.cxx
diff options
context:
space:
mode:
authorAmlal El Mahrouss <amlal.elmahrouss@icloud.com>2024-05-09 00:42:44 +0200
committerAmlal El Mahrouss <amlal.elmahrouss@icloud.com>2024-05-09 00:42:44 +0200
commitaf8a516fc22865abd80d6e26f1541fa3d6bebfdc (patch)
tree96d42a10945fc03df022389aef54708383c1d616 /Kernel/Source/ProcessScheduler.cxx
parenta874e9cc98df994178d55996943fe81799c61d2f (diff)
MHR-23: :boom:, refactors.
- Move NewBoot to /Boot, thus making Kernel directory only containing the kernel. Signed-off-by: Amlal El Mahrouss <amlal.elmahrouss@icloud.com>
Diffstat (limited to 'Kernel/Source/ProcessScheduler.cxx')
-rw-r--r--Kernel/Source/ProcessScheduler.cxx392
1 files changed, 392 insertions, 0 deletions
diff --git a/Kernel/Source/ProcessScheduler.cxx b/Kernel/Source/ProcessScheduler.cxx
new file mode 100644
index 00000000..859ce657
--- /dev/null
+++ b/Kernel/Source/ProcessScheduler.cxx
@@ -0,0 +1,392 @@
+/* -------------------------------------------
+
+ Copyright SoftwareLabs
+
+------------------------------------------- */
+
+/***********************************************************************************/
+/// @file ProcessScheduler.cxx
+/// @brief MicroKernel process scheduler.
+/***********************************************************************************/
+
+#include <KernelKit/ProcessScheduler.hpp>
+#include <KernelKit/SMPManager.hpp>
+#include <KernelKit/KernelHeap.hpp>
+#include <NewKit/String.hpp>
+#include <KernelKit/HError.hpp>
+
+///! BUGS: 0
+
+/***********************************************************************************/
+/* This file handles the process scheduling.
+/***********************************************************************************/
+
+namespace NewOS
+{
+ /***********************************************************************************/
+ /// @brief Exit Code global
+ /***********************************************************************************/
+
+ STATIC Int32 kLastExitCode = 0U;
+
+ /// @brief Gets the latest exit code.
+ /// @note Not thread-safe.
+ const Int32& rt_get_exit_code() noexcept
+ {
+ return kLastExitCode;
+ }
+
+ /***********************************************************************************/
+ /// @brief crash current process.
+ /***********************************************************************************/
+
+ void ProcessHeader::Crash()
+ {
+ kcout << this->Name << ": crashed. (id = " << number(39);
+ kcout << ")\r";
+
+ if (this->Ring != kRingUserKind)
+ {
+ MUST_PASS(ke_bug_check());
+ }
+
+ this->Exit(kErrorProcessFault);
+ }
+
+ void ProcessHeader::Wake(const bool should_wakeup)
+ {
+ this->Status =
+ should_wakeup ? ProcessStatus::kRunning : ProcessStatus::kFrozen;
+ }
+
+ /***********************************************************************************/
+
+ VoidPtr ProcessHeader::New(const SizeT& sz)
+ {
+ if (this->FreeMemory < 1)
+ {
+ DbgLastError() = kErrorHeapOutOfMemory;
+ this->Crash(); /// out of memory.
+
+ return nullptr;
+ }
+
+ if (this->HeapCursor)
+ {
+ VoidPtr ptr = this->HeapCursor;
+ this->HeapCursor = (VoidPtr)((UIntPtr)this->HeapCursor + (sizeof(sz)));
+
+ ++this->UsedMemory;
+ --this->FreeMemory;
+
+ return ptr;
+ }
+
+ return nullptr;
+ }
+
+ /***********************************************************************************/
+
+ /* @brief checks if runtime pointer is in region. */
+ bool rt_is_in_pool(VoidPtr pool_ptr, VoidPtr pool, const SizeT& sz)
+ {
+ UIntPtr* _pool_ptr = (UIntPtr*)pool_ptr;
+ UIntPtr* _pool = (UIntPtr*)pool;
+
+ for (SizeT index = sz; _pool[sz] != kUserHeapMag; --index)
+ {
+ if (&_pool[index] > &_pool_ptr[sz])
+ continue;
+
+ if (_pool[index] == _pool_ptr[index])
+ return true;
+ }
+
+ return false;
+ }
+
+ /* @brief free pointer from usage. */
+ Boolean ProcessHeader::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->HeapCursor = (VoidPtr)((UIntPtr)this->HeapCursor - (sizeof(sz)));
+ rt_zero_memory(ptr, sz);
+
+ ++this->FreeMemory;
+ --this->UsedMemory;
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /// @brief process name getter.
+ const Char* ProcessHeader::GetName()
+ {
+ return this->Name;
+ }
+
+ /// @brief process selector getter.
+ const ProcessSelector& ProcessHeader::GetSelector()
+ {
+ return this->Selector;
+ }
+
+ /// @brief process status getter.
+ const ProcessStatus& ProcessHeader::GetStatus()
+ {
+ return this->Status;
+ }
+
+ /***********************************************************************************/
+
+ /**
+@brief Affinity is the time slot allowed for the process.
+*/
+ const AffinityKind& ProcessHeader::GetAffinity()
+ {
+ return this->Affinity;
+ }
+
+ /**
+@brief Standard exit proc.
+*/
+ void ProcessHeader::Exit(Int32 exit_code)
+ {
+ if (this->ProcessId !=
+ ProcessScheduler::Shared().Leak().GetCurrent().Leak().ProcessId)
+ ke_stop(RUNTIME_CHECK_PROCESS);
+
+ if (this->Ring == (Int32)ProcessSelector::kRingKernel &&
+ ProcessScheduler::Shared().Leak().GetCurrent().Leak().Ring > 0)
+ ke_stop(RUNTIME_CHECK_PROCESS);
+
+ kLastExitCode = exit_code;
+
+ if (this->Ring != (Int32)ProcessSelector::kRingDriver)
+ {
+ if (this->HeapPtr)
+ rt_free_heap(this->HeapPtr);
+
+ this->HeapPtr = nullptr;
+ this->HeapCursor = nullptr;
+
+ this->FreeMemory = 0UL;
+ this->UsedMemory = 0UL;
+ }
+
+ //! Delete image if not done already.
+ if (this->Image)
+ ke_delete_ke_heap(this->Image);
+ if (this->StackFrame)
+ ke_delete_ke_heap((VoidPtr)this->StackFrame);
+
+ this->Image = nullptr;
+ this->StackFrame = nullptr;
+
+ ProcessScheduler::Shared().Leak().Remove(this->ProcessId);
+ }
+
+ SizeT ProcessScheduler::Add(Ref<ProcessHeader>& process)
+ {
+ if (!process)
+ return -1;
+
+ if (!process.Leak().Image)
+ {
+ if (process.Leak().Kind != ProcessHeader::kLibKind)
+ {
+ return -kErrorNoEntrypoint;
+ }
+ }
+
+ if (!mTeam.AsArray().Count() > kSchedProcessLimitPerTeam)
+ return -kErrorOutOfTeamSlot;
+
+ if (process.Leak().Ring != (Int32)ProcessSelector::kRingKernel)
+ return -1;
+
+ kcout << "ProcessScheduler::Add(Ref<ProcessHeader>& process)\r";
+
+ /// Create heap according to type of process.
+ if (process.Leak().Kind == ProcessHeader::kUserKind)
+ process.Leak().HeapPtr = rt_new_heap(kUserHeapUser | kUserHeapRw);
+ else if (process.Leak().Kind == ProcessHeader::kLibKind)
+ process.Leak().HeapPtr = rt_new_heap(kUserHeapUser | kUserHeapRw | kUserHeapShared);
+ else
+ process.Leak().HeapPtr = rt_new_heap(kUserHeapDriver | kUserHeapRw);
+
+ process.Leak().StackFrame = reinterpret_cast<HAL::StackFrame*>(
+ ke_new_ke_heap(sizeof(HAL::StackFrame), true, false));
+
+ MUST_PASS(process.Leak().StackFrame);
+
+ mTeam.AsArray().Add(process);
+
+ process.Leak().ProcessId = mTeam.AsArray().Count() - 1;
+ process.Leak().HeapCursor = process.Leak().HeapPtr;
+
+ return mTeam.AsArray().Count() - 1;
+ }
+
+ bool ProcessScheduler::Remove(SizeT process)
+ {
+ if (process > mTeam.AsArray().Count())
+ return false;
+
+ kcout << "ProcessScheduler::Remove(SizeT process)\r";
+
+ return mTeam.AsArray().Remove(process);
+ }
+
+ SizeT ProcessScheduler::Run() noexcept
+ {
+ SizeT processIndex = 0; //! we store this guy to tell the scheduler how many
+ //! things we have scheduled.
+
+ for (; processIndex < mTeam.AsArray().Count(); ++processIndex)
+ {
+ auto process = mTeam.AsArray()[processIndex];
+
+ MUST_PASS(process); //! no need for a MUST_PASS(process.Leak());, it is
+ //! recursive because of the nature of the class;
+
+ //! run any process needed to be scheduled.
+ if (ProcessHelper::CanBeScheduled(process.Leak()))
+ {
+ auto unwrapped_process = *process.Leak();
+
+ unwrapped_process.PTime = 0;
+
+ // set the current process.
+ mTeam.AsRef() = unwrapped_process;
+
+ // tell helper to find a core to schedule on.
+ ProcessHelper::Switch(mTeam.AsRef().Leak().StackFrame,
+ mTeam.AsRef().Leak().ProcessId);
+ }
+ else
+ {
+ // otherwise increment the P-time.
+ ++mTeam.AsRef().Leak().PTime;
+ }
+ }
+
+ return processIndex;
+ }
+
+ Ref<ProcessScheduler> ProcessScheduler::Shared()
+ {
+ static ProcessScheduler ref;
+ return {ref};
+ }
+
+ /// @brief Gets current running process.
+ /// @return
+ Ref<ProcessHeader>& ProcessScheduler::GetCurrent()
+ {
+ return mTeam.AsRef();
+ }
+
+ PID& ProcessHelper::GetCurrentPID()
+ {
+ kcout << "ProcessHelper::GetCurrentPID: Leaking ProcessId...\r";
+ return ProcessScheduler::Shared().Leak().GetCurrent().Leak().ProcessId;
+ }
+
+ bool ProcessHelper::CanBeScheduled(Ref<ProcessHeader>& process)
+ {
+ if (process.Leak().Status == ProcessStatus::kFrozen ||
+ process.Leak().Status == ProcessStatus::kDead)
+ return false;
+
+ if (process.Leak().GetStatus() == ProcessStatus::kStarting)
+ {
+ if (process.Leak().PTime < static_cast<Int>(kSchedMinMicroTime))
+ {
+ process.Leak().Status = ProcessStatus::kRunning;
+ process.Leak().Affinity = AffinityKind::kHartStandard;
+
+ return true;
+ }
+
+ ++process.Leak().PTime;
+ }
+
+ return process.Leak().PTime > static_cast<Int>(kSchedMinMicroTime);
+ }
+
+ /**
+ * @brief Spin scheduler class.
+ */
+ bool ProcessHelper::StartScheduling()
+ {
+ if (ProcessHelper::CanBeScheduled(
+ ProcessScheduler::Shared().Leak().GetCurrent()))
+ {
+ --ProcessScheduler::Shared().Leak().GetCurrent().Leak().PTime;
+ return false;
+ }
+
+ auto processRef = ProcessScheduler::Shared().Leak();
+
+ if (!processRef)
+ return false; // we have nothing to schedule. simply return.
+
+ SizeT ret = processRef.Run();
+
+ kcout << StringBuilder::FromInt(
+ "ProcessHelper::StartScheduling() Iterated over {%} jobs inside team.\r", ret);
+
+ return true;
+ }
+
+ /**
+ * \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;
+
+ for (SizeT index = 0UL; index < SMPManager::Shared().Leak().Count(); ++index)
+ {
+ if (SMPManager::Shared().Leak()[index].Leak().Kind() == kInvalidHart)
+ continue;
+
+ if (SMPManager::Shared().Leak()[index].Leak().StackFrame() == the_stack)
+ {
+ SMPManager::Shared().Leak()[index].Leak().Busy(false);
+ continue;
+ }
+
+ if (SMPManager::Shared().Leak()[index].Leak().IsBusy())
+ continue;
+
+ if (SMPManager::Shared().Leak()[index].Leak().Kind() !=
+ ThreadKind::kHartBoot &&
+ SMPManager::Shared().Leak()[index].Leak().Kind() !=
+ ThreadKind::kHartSystemReserved)
+ {
+ SMPManager::Shared().Leak()[index].Leak().Busy(true);
+ ProcessHelper::GetCurrentPID() = new_pid;
+
+ return SMPManager::Shared().Leak()[index].Leak().Switch(the_stack);
+ }
+ }
+
+ return false;
+ }
+} // namespace NewOS