diff options
Diffstat (limited to 'dev/kernel/src/UserProcessScheduler.cc')
| -rw-r--r-- | dev/kernel/src/UserProcessScheduler.cc | 1138 |
1 files changed, 612 insertions, 526 deletions
diff --git a/dev/kernel/src/UserProcessScheduler.cc b/dev/kernel/src/UserProcessScheduler.cc index 5e8cc89e..45a95b5b 100644 --- a/dev/kernel/src/UserProcessScheduler.cc +++ b/dev/kernel/src/UserProcessScheduler.cc @@ -1,9 +1,9 @@ /* ------------------------------------------- - Copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. + Copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. - FILE: UserProcessScheduler.cc - PURPOSE: Low level/Ring-3 Process scheduler. + FILE: UserProcessScheduler.cc + PURPOSE: Low level/Ring-3 process scheduler. ------------------------------------------- */ @@ -13,609 +13,695 @@ /// @author Amlal El Mahrouss (amlal@nekernel.org) /***********************************************************************************/ -#include <KernelKit/ProcessScheduler.h> +#include <ArchKit/ArchKit.h> #include <KernelKit/HardwareThreadScheduler.h> #include <KernelKit/IPEFDylibObject.h> -#include <ArchKit/ArchKit.h> +#include <KernelKit/KPC.h> #include <KernelKit/MemoryMgr.h> +#include <KernelKit/ProcessScheduler.h> #include <NewKit/KString.h> -#include <KernelKit/KPC.h> ///! BUGS: 0 -namespace Kernel -{ - /***********************************************************************************/ - /// @brief Exit Code global variable. - /***********************************************************************************/ - - STATIC UInt32 kLastExitCode = 0U; - - /***********************************************************************************/ - /// @brief External reference of the thread scheduler. - /***********************************************************************************/ - - STATIC UserProcessScheduler kProcessScheduler; - - Process::Process() = default; - Process::~Process() = default; - - /// @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 kLastExitCode; - } - - /***********************************************************************************/ - /// @brief Crashes the current process. - /***********************************************************************************/ - - Void Process::Crash() - { - if (this->Status != ProcessStatusKind::kRunning) - return; - - (void)(kout << this->Name << ": crashed, error id: " << number(kErrorProcessFault) << kendl); - this->Exit(kErrorProcessFault); - } - - /***********************************************************************************/ - /// @brief boolean operator, check status. - /***********************************************************************************/ - - Process::operator bool() - { - return this->Status == ProcessStatusKind::kRunning; - } - - /***********************************************************************************/ - /// @brief Gets the local last exit code. - /// @note Not thread-safe. - /// @return Int32 the last exit code. - /***********************************************************************************/ - - const UInt32& Process::GetExitCode() noexcept - { - return this->fLastExitCode; - } - - /***********************************************************************************/ - /// @brief Error code variable getter. - /***********************************************************************************/ - - Int32& Process::GetLocalCode() noexcept - { - return this->fLocalCode; - } - - /***********************************************************************************/ - /// @brief Wakes process header. - /// @param should_wakeup if the program shall wakeup or not. - /***********************************************************************************/ - - Void Process::Wake(Bool should_wakeup) - { - this->Status = - should_wakeup ? ProcessStatusKind::kRunning : ProcessStatusKind::kFrozen; - } - - /***********************************************************************************/ - /** @brief Allocate pointer to track list. */ - /***********************************************************************************/ - - ErrorOr<VoidPtr> Process::New(SizeT sz, SizeT pad_amount) - { +namespace Kernel { +/***********************************************************************************/ +/// @brief Exit Code global variable. +/***********************************************************************************/ + +STATIC UInt32 kLastExitCode = 0U; + +STATIC BOOL kCurrentlySwitching = No; + +/***********************************************************************************/ +/// @brief Scheduler itself. +/***********************************************************************************/ + +STATIC UserProcessScheduler kScheduler; + +USER_PROCESS::USER_PROCESS() = default; +USER_PROCESS::~USER_PROCESS() = default; + +/// @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 kLastExitCode; +} + +/***********************************************************************************/ +/// @brief Crashes the current process. +/***********************************************************************************/ + +Void USER_PROCESS::Crash() { + if (this->Status != ProcessStatusKind::kRunning) return; + + (Void)(kout << this->Name << ": crashed, error id: " << number(-kErrorProcessFault) << kendl); + this->Exit(-kErrorProcessFault); +} + +/***********************************************************************************/ +/// @brief boolean operator, check status. +/***********************************************************************************/ + +USER_PROCESS::operator bool() { + return this->Status == ProcessStatusKind::kRunning; +} + +/***********************************************************************************/ +/// @brief Gets the local last exit code. +/// @note Not thread-safe. +/// @return Int32 the last exit code. +/***********************************************************************************/ + +const UInt32& USER_PROCESS::GetExitCode() noexcept { + return this->fLastExitCode; +} + +/***********************************************************************************/ +/// @brief Error code variable getter. +/***********************************************************************************/ + +Int32& USER_PROCESS::GetLocalCode() noexcept { + return this->fLocalCode; +} + +/***********************************************************************************/ +/// @brief Wakes process header. +/// @param should_wakeup if the program shall wakeup or not. +/***********************************************************************************/ + +Void USER_PROCESS::Wake(Bool should_wakeup) { + this->Status = should_wakeup ? ProcessStatusKind::kRunning : ProcessStatusKind::kFrozen; +} + +/***********************************************************************************/ +/** @brief Allocate pointer to heap tree. */ +/***********************************************************************************/ + +STATIC USER_PROCESS::USER_HEAP_TREE* sched_try_go_upper_heap_tree( + USER_PROCESS::USER_HEAP_TREE* tree) { + if (!tree) { + return nullptr; + } + + tree = tree->MemoryParent; + + if (tree) { + auto tree_tmp = tree->MemoryNext; + + if (!tree_tmp) { + return tree; + } + + return tree_tmp; + } + + return tree; +} + +/***********************************************************************************/ +/** @brief Allocate pointer to heap tree. */ +/***********************************************************************************/ + +ErrorOr<VoidPtr> USER_PROCESS::New(SizeT sz, SizeT pad_amount) { + if (this->UsedMemory > kSchedMaxMemoryLimit) return ErrorOr<VoidPtr>(-kErrorHeapOutOfMemory); + #ifdef __NE_VIRTUAL_MEMORY_SUPPORT__ - auto vm_register = hal_read_cr3(); - hal_write_cr3(this->VMRegister); + auto vm_register = kKernelCR3; + hal_write_cr3(this->VMRegister); - auto ptr = mm_new_heap(sz, Yes, Yes, pad_amount); + auto ptr = mm_new_heap(sz, Yes, Yes, pad_amount); - hal_write_cr3(vm_register); + hal_write_cr3(vm_register); #else - auto ptr = mm_new_heap(sz, Yes, Yes, pad_amount); + auto ptr = mm_new_heap(sz, Yes, Yes, pad_amount); #endif - if (!this->ProcessMemoryHeap) - { - this->ProcessMemoryHeap = new ProcessMemoryHeapList(); + if (!this->HeapTree) { + this->HeapTree = new USER_HEAP_TREE(); + + this->HeapTree->MemoryColor = USER_HEAP_TREE::kBlackMemory; + + this->HeapTree->MemoryEntryPad = pad_amount; + this->HeapTree->MemoryEntrySize = sz; + + this->HeapTree->MemoryEntry = ptr; + + this->HeapTree->MemoryPrev = nullptr; + this->HeapTree->MemoryNext = nullptr; + this->HeapTree->MemoryParent = nullptr; + this->HeapTree->MemoryChild = nullptr; + } else { + USER_HEAP_TREE* entry = this->HeapTree; + USER_HEAP_TREE* prev_entry = entry; - this->ProcessMemoryHeap->MemoryEntryPad = pad_amount; - this->ProcessMemoryHeap->MemoryEntrySize = sz; + BOOL is_parent = NO; - this->ProcessMemoryHeap->MemoryEntry = ptr; + while (entry) { + if (entry->MemoryEntrySize < 1) break; - this->ProcessMemoryHeap->MemoryPrev = nullptr; - this->ProcessMemoryHeap->MemoryNext = nullptr; - } - else - { - ProcessMemoryHeapList* entry = this->ProcessMemoryHeap; + prev_entry = entry; - while (entry) - { - if (entry->MemoryEntry == nullptr) - break; // chose to break here, when we get an already allocated memory entry for our needs. + if (entry->MemoryNext) { + is_parent = NO; + entry = entry->MemoryNext; + } else if (entry->MemoryChild) { + entry = entry->MemoryChild; + is_parent = YES; + } else { + entry = sched_try_go_upper_heap_tree(entry); + } + } - entry = entry->MemoryNext; - } + if (!entry) entry = new USER_HEAP_TREE(); - entry->MemoryNext = new ProcessMemoryHeapList(); - entry->MemoryNext->MemoryEntry = ptr; + entry->MemoryEntry = ptr; + entry->MemoryEntrySize = sz; + entry->MemoryEntryPad = pad_amount; - entry->MemoryNext->MemoryPrev = entry; - entry->MemoryNext->MemoryNext = nullptr; - } + if (is_parent) { + entry->MemoryParent = prev_entry; + prev_entry->MemoryChild = entry; - this->UsedMemory += sz; + prev_entry->MemoryColor = USER_HEAP_TREE::kBlackMemory; + entry->MemoryColor = USER_HEAP_TREE::kRedMemory; + } else { + prev_entry->MemoryNext = entry; + entry->MemoryPrev = prev_entry; + } + } - return ErrorOr<VoidPtr>(ptr); - } + this->UsedMemory += sz; + + return ErrorOr<VoidPtr>(ptr); +} + +/***********************************************************************************/ +/// @brief Gets the name of the current process. +/***********************************************************************************/ + +const Char* USER_PROCESS::GetName() noexcept { + return this->Name; +} + +/***********************************************************************************/ +/// @brief Gets the owner of the process. +/***********************************************************************************/ + +const User* USER_PROCESS::GetOwner() noexcept { + return this->Owner; +} + +/// @brief USER_PROCESS status getter. +const ProcessStatusKind& USER_PROCESS::GetStatus() noexcept { + return this->Status; +} + +/***********************************************************************************/ +/** +@brief Affinity is the time slot allowed for the process. +*/ +/***********************************************************************************/ - /***********************************************************************************/ - /// @brief Gets the name of the current process. - /***********************************************************************************/ +const AffinityKind& USER_PROCESS::GetAffinity() noexcept { + return this->Affinity; +} - const Char* Process::GetName() noexcept - { - return this->Name; - } +/***********************************************************************************/ +/** @brief Free heap tree. */ +/***********************************************************************************/ - /***********************************************************************************/ - /// @brief Gets the owner of the process. - /***********************************************************************************/ +STATIC Void sched_free_heap_tree(USER_PROCESS::USER_HEAP_TREE* memory_heap_list) { + // Deleting memory lists. Make sure to free all of them. + while (memory_heap_list) { + if (memory_heap_list->MemoryEntry) { + MUST_PASS(mm_delete_heap(memory_heap_list->MemoryEntry)); + } - const User* Process::GetOwner() noexcept - { - return this->Owner; - } + auto next = memory_heap_list->MemoryNext; - /// @brief Process status getter. - const ProcessStatusKind& Process::GetStatus() noexcept - { - return this->Status; - } + mm_delete_heap(memory_heap_list); - /***********************************************************************************/ - /** - @brief Affinity is the time slot allowed for the process. - */ - /***********************************************************************************/ + if (memory_heap_list->MemoryChild) sched_free_heap_tree(memory_heap_list->MemoryChild); - const AffinityKind& Process::GetAffinity() noexcept - { - return this->Affinity; - } + memory_heap_list = next; + } +} - /***********************************************************************************/ - /** - @brief Exit process method. - @param exit_code The process's exit code. - */ - /***********************************************************************************/ +/***********************************************************************************/ +/** +@brief Exit process method. +@param exit_code The process's exit code. +*/ +/***********************************************************************************/ - Void Process::Exit(const Int32& exit_code) - { - this->Status = exit_code > 0 ? ProcessStatusKind::kKilled : ProcessStatusKind::kFrozen; - this->fLastExitCode = exit_code; +Void USER_PROCESS::Exit(const Int32& exit_code) { + this->Status = exit_code > 0 ? ProcessStatusKind::kKilled : ProcessStatusKind::kFrozen; + this->fLastExitCode = exit_code; - kLastExitCode = exit_code; + kLastExitCode = exit_code; - auto memory_heap_list = this->ProcessMemoryHeap; + auto memory_heap_list = this->HeapTree; #ifdef __NE_VIRTUAL_MEMORY_SUPPORT__ - auto pd = hal_read_cr3(); - hal_write_cr3(this->VMRegister); + auto pd = kKernelCR3; + hal_write_cr3(this->VMRegister); #endif - // Deleting memory lists. Make sure to free all of them. - while (memory_heap_list) - { - if (memory_heap_list->MemoryEntry) - { - MUST_PASS(mm_delete_heap(memory_heap_list->MemoryEntry)); - } + sched_free_heap_tree(memory_heap_list); #ifdef __NE_VIRTUAL_MEMORY_SUPPORT__ - hal_write_cr3(pd); + hal_write_cr3(pd); #endif - auto next = memory_heap_list->MemoryNext; +#ifdef __NE_VIRTUAL_MEMORY_SUPPORT__ + //! Free the memory's page directory. + if (this->VMRegister) HAL::mm_free_bitmap(this->VMRegister); +#endif - mm_delete_heap(memory_heap_list); + //! Delete image if not done already. + if (this->Image.fCode && mm_is_valid_heap(this->Image.fCode)) mm_delete_heap(this->Image.fCode); - memory_heap_list = next; - } + //! Delete blob too. + if (this->Image.fBlob && mm_is_valid_heap(this->Image.fBlob)) mm_delete_heap(this->Image.fBlob); - //! Free the memory's page directory. - HAL::mm_free_bitmap(this->VMRegister); + //! Delete stack frame. + if (this->StackFrame && mm_is_valid_heap(this->StackFrame)) + mm_delete_heap((VoidPtr) this->StackFrame); - //! Delete image if not done already. - if (this->Image.fCode && mm_is_valid_heap(this->Image.fCode)) - mm_delete_heap(this->Image.fCode); + //! Delete stack reserve. + if (this->StackReserve && mm_is_valid_heap(this->StackReserve)) + mm_delete_heap(reinterpret_cast<VoidPtr>(this->StackReserve)); - //! Delete blob too. - if (this->Image.fBlob && mm_is_valid_heap(this->Image.fBlob)) - mm_delete_heap(this->Image.fBlob); + //! Avoid use after free. + this->Image.fBlob = nullptr; + this->Image.fCode = nullptr; + this->StackFrame = nullptr; + this->StackReserve = nullptr; - //! Delete stack frame. - if (this->StackFrame && mm_is_valid_heap(this->StackFrame)) - mm_delete_heap((VoidPtr)this->StackFrame); + if (this->Kind == kExecutableDylibKind) { + Bool success = false; - //! Delete stack reserve. - if (this->StackReserve && mm_is_valid_heap(this->StackReserve)) - mm_delete_heap(reinterpret_cast<VoidPtr>(this->StackReserve)); + rtl_fini_dylib_pef(*this, reinterpret_cast<IPEFDylibObject*>(this->DylibDelegate), &success); - //! Avoid use after free. - this->Image.fBlob = nullptr; - this->Image.fCode = nullptr; - this->StackFrame = nullptr; - this->StackReserve = nullptr; + if (!success) { + ke_panic(RUNTIME_CHECK_PROCESS); + } - if (this->Kind == kExecutableDylibKind) - { - Bool success = false; + this->DylibDelegate = nullptr; + } - rtl_fini_dylib(*this, reinterpret_cast<IPEFDylibObject*>(this->DylibDelegate), &success); + this->ProcessId = 0UL; + this->Status = ProcessStatusKind::kFinished; - if (!success) - { - ke_panic(RUNTIME_CHECK_PROCESS); - } + --this->ParentTeam->mProcessCount; +} - this->DylibDelegate = nullptr; - } +/***********************************************************************************/ +/// @brief Add process to team. +/// @param process the process *Ref* class. +/// @return the process index inside the team. +/***********************************************************************************/ - this->ProcessId = 0UL; - this->Status = ProcessStatusKind::kFinished; +ProcessID UserProcessScheduler::Spawn(const Char* name, VoidPtr code, VoidPtr image) { + if (!name || !code) { + return -kErrorProcessFault; + } - --this->ProcessParentTeam->mProcessCount; + if (*name == 0) { + return -kErrorProcessFault; + } - delete this; - } + ProcessID pid = this->mTeam.mProcessCount; - /***********************************************************************************/ - /// @brief Add process to team. - /// @param process the process *Ref* class. - /// @return the process index inside the team. - /***********************************************************************************/ + if (pid > kSchedProcessLimitPerTeam) { + return -kErrorProcessFault; + } - ProcessID UserProcessScheduler::Spawn(const Char* name, VoidPtr code, VoidPtr image) - { - ProcessID pid = this->mTeam.mProcessCount; + ++this->mTeam.mProcessCount; - if (pid > kSchedProcessLimitPerTeam) - { - return kErrorProcessFault; - } + USER_PROCESS& process = this->mTeam.mProcessList[pid]; - ++this->mTeam.mProcessCount; + process.Image.fCode = code; + process.Image.fBlob = image; - Process& process = this->mTeam.mProcessList[pid]; + SizeT len = rt_string_len(name); - process.Image.fCode = code; - process.Image.fBlob = image; + if (len > kSchedNameLen) { + return -kErrorProcessFault; + } - rt_copy_memory(reinterpret_cast<VoidPtr>(const_cast<Char*>(name)), process.Name, rt_string_len(name)); + rt_copy_memory(reinterpret_cast<VoidPtr>(const_cast<Char*>(name)), process.Name, len); #ifdef __NE_VIRTUAL_MEMORY_SUPPORT__ - process.VMRegister = new PDE(); + process.VMRegister = new PDE(); - if (!process.VMRegister) - { - process.Crash(); - return kErrorProcessFault; - } + if (!process.VMRegister) { + process.Crash(); + return -kErrorProcessFault; + } - UInt32 flags = HAL::kMMFlagsPresent; - flags |= HAL::kMMFlagsWr; - flags |= HAL::kMMFlagsUser; + UInt32 flags = HAL::kMMFlagsPresent; + flags |= HAL::kMMFlagsWr; + flags |= HAL::kMMFlagsUser; - HAL::mm_map_page((VoidPtr)process.VMRegister, process.VMRegister, flags); -#endif // ifdef __NE_VIRTUAL_MEMORY_SUPPORT__ + HAL::mm_map_page((VoidPtr) process.VMRegister, process.VMRegister, flags); +#endif // ifdef __NE_VIRTUAL_MEMORY_SUPPORT__ - process.StackFrame = new HAL::StackFrame(); + process.StackFrame = new HAL::StackFrame(); - if (!process.StackFrame) - { - process.Crash(); - return kErrorProcessFault; - } + if (!process.StackFrame) { + process.Crash(); + return -kErrorProcessFault; + } - rt_set_memory(process.StackFrame, 0, sizeof(HAL::StackFrame)); + rt_set_memory(process.StackFrame, 0, sizeof(HAL::StackFrame)); #ifdef __NE_VIRTUAL_MEMORY_SUPPORT__ - flags = HAL::kMMFlagsPresent; - flags |= HAL::kMMFlagsWr; - flags |= HAL::kMMFlagsUser; - - HAL::mm_map_page((VoidPtr)process.StackFrame, process.StackFrame, flags); -#endif // ifdef __NE_VIRTUAL_MEMORY_SUPPORT__ - - // React according to process kind. - switch (process.Kind) - { - case Process::kExecutableDylibKind: { - process.DylibDelegate = rtl_init_dylib(process); - MUST_PASS(process.DylibDelegate); - break; - } - case Process::kExecutableKind: { - break; - } - default: { - (void)(kout << "Unknown process kind: " << hex_number(process.Kind) << kendl); - break; - } - } - - process.StackReserve = new UInt8[process.StackSize]; - - if (!process.StackReserve) - { - process.Crash(); - return kErrorProcessFault; - } - - rt_set_memory(process.StackReserve, 0, process.StackSize); + flags = HAL::kMMFlagsPresent; + flags |= HAL::kMMFlagsWr; + flags |= HAL::kMMFlagsUser; + + HAL::mm_map_page((VoidPtr) process.StackFrame, process.StackFrame, flags); +#endif // ifdef __NE_VIRTUAL_MEMORY_SUPPORT__ + + // React according to process kind. + switch (process.Kind) { + case USER_PROCESS::kExecutableDylibKind: { + process.DylibDelegate = rtl_init_dylib_pef(process); + MUST_PASS(process.DylibDelegate); + break; + } + case USER_PROCESS::kExecutableKind: { + break; + } + default: { + (Void)(kout << "Unknown process kind: " << hex_number(process.Kind) << kendl); + break; + } + } + + process.StackReserve = new UInt8[process.StackSize]; + + if (!process.StackReserve) { + process.Crash(); + return -kErrorProcessFault; + } + + rt_set_memory(process.StackReserve, 0, process.StackSize); #ifdef __NE_VIRTUAL_MEMORY_SUPPORT__ - flags = HAL::kMMFlagsPresent; - flags |= HAL::kMMFlagsWr; - flags |= HAL::kMMFlagsUser; + flags = HAL::kMMFlagsPresent; + flags |= HAL::kMMFlagsWr; + flags |= HAL::kMMFlagsUser; + + HAL::mm_map_page((VoidPtr) process.StackReserve, process.StackReserve, flags); +#endif // ifdef __NE_VIRTUAL_MEMORY_SUPPORT__ + + process.ParentTeam = &mTeam; + + process.ProcessId = pid; + process.Status = ProcessStatusKind::kStarting; + process.PTime = (UIntPtr) AffinityKind::kStandard; + process.RTime = 0; + + (Void)(kout << "PID: " << number(process.ProcessId) << kendl); + (Void)(kout << "Name: " << process.Name << kendl); + + return pid; +} + +/***********************************************************************************/ +/// @brief Retrieves the singleton of the process scheduler. +/***********************************************************************************/ + +UserProcessScheduler& UserProcessScheduler::The() { + return kScheduler; +} + +/***********************************************************************************/ + +/// @brief Remove process from the team. +/// @param process_id process slot inside team. +/// @retval true process was removed. +/// @retval false process doesn't exist in team. + +/***********************************************************************************/ + +Void UserProcessScheduler::Remove(ProcessID process_id) { + if (process_id < 0 || process_id >= kSchedProcessLimitPerTeam) { + return; + } + + if (this->mTeam.mProcessList[process_id].Status == ProcessStatusKind::kInvalid) { + return; + } + + mTeam.mProcessList[process_id].Exit(0); +} + +/// @brief Is it a user scheduler? + +Bool UserProcessScheduler::IsUser() { + return Yes; +} + +/// @brief Is it a kernel scheduler? + +Bool UserProcessScheduler::IsKernel() { + return No; +} + +/// @brief Is it a SMP scheduler? + +Bool UserProcessScheduler::HasMP() { + MUST_PASS(kHandoverHeader); + return kHandoverHeader->f_HardwareTables.f_MultiProcessingEnabled; +} + +/***********************************************************************************/ +/// @brief Run User scheduler object. +/// @return USER_PROCESS count executed within a team. +/***********************************************************************************/ + +SizeT UserProcessScheduler::Run() noexcept { + if (mTeam.mProcessCount < 1) { + return 0UL; + } + + if (kCurrentlySwitching) return 0UL; + + kCurrentlySwitching = Yes; + + SizeT process_index = 0UL; //! 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 the process needs to be run. + if (UserProcessHelper::CanBeScheduled(process)) { + if (process.StackSize > kSchedMaxStackSz) { + kout << "The process: " << process.Name << ", has not a valid stack size! Crashing it...\r"; + process.Crash(); + continue; + } + + // Set current process header. + this->CurrentProcess() = process; + + process.PTime = static_cast<Int32>(process.Affinity); + + // tell helper to find a core to schedule on. + BOOL ret = UserProcessHelper::Switch(process.Image.Leak().Leak().Leak(), + &process.StackReserve[process.StackSize - 1], + process.StackFrame, process.ProcessId); + + if (!ret) { + kout << "The process: " << process.Name << ", is not valid! Crashing it...\r"; + process.Crash(); + } + } else { + if (process.ProcessId == this->CurrentProcess().Leak().ProcessId) { + if (process.PTime < process.RTime) { + if (process.RTime < (Int32) AffinityKind::kRealTime) + process.PTime = (Int32) AffinityKind::kVeryLowUsage; + else if (process.RTime < (Int32) AffinityKind::kVeryHigh) + process.PTime = (Int32) AffinityKind::kLowUsage; + else if (process.RTime < (Int32) AffinityKind::kHigh) + process.PTime = (Int32) AffinityKind::kStandard; + else if (process.RTime < (Int32) AffinityKind::kStandard) + process.PTime = (Int32) AffinityKind::kHigh; + + process.RTime = static_cast<Int32>(process.Affinity); + + BOOL ret = UserProcessHelper::Switch(process.Image.Leak().Leak().Leak(), + &process.StackReserve[process.StackSize - 1], + process.StackFrame, process.ProcessId); + + if (!ret) { + kout << "The process: " << process.Name << ", is not valid! Crashing it...\r"; + process.Crash(); + } + } else { + ++process.RTime; + } + } + + --process.PTime; + } + } + + kCurrentlySwitching = No; + + return process_index; +} + +/// @brief Gets the current scheduled team. +/// @return +UserProcessTeam& UserProcessScheduler::CurrentTeam() { + return mTeam; +} + +/***********************************************************************************/ +/// @brief Switches the current team. +/// @param team the new team to switch to. +/// @retval true team was switched. +/// @retval false team was not switched. +/***********************************************************************************/ + +BOOL UserProcessScheduler::SwitchTeam(UserProcessTeam& team) { + if (team.AsArray().Count() < 1) return No; + + if (kCurrentlySwitching) return No; + + kScheduler.mTeam = team; + + return Yes; +} + +/// @brief Gets current running process. +/// @return +Ref<USER_PROCESS>& UserProcessScheduler::CurrentProcess() { + return mTeam.AsRef(); +} + +/// @brief Current proccess id getter. +/// @return USER_PROCESS ID integer. +ErrorOr<PID> UserProcessHelper::TheCurrentPID() { + if (!kScheduler.CurrentProcess()) return ErrorOr<PID>{-kErrorProcessFault}; + + kout << "UserProcessHelper::TheCurrentPID: Leaking ProcessId...\r"; + return ErrorOr<PID>{kScheduler.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 USER_PROCESS& process) { + if (process.Status == ProcessStatusKind::kKilled || + process.Status == ProcessStatusKind::kFinished || + process.Status == ProcessStatusKind::kStarting || + process.Status == ProcessStatusKind::kFrozen) + return No; + + if (process.Status == ProcessStatusKind::kInvalid) return No; + + if (!process.Image.HasCode()) return No; + + if (!process.Name[0]) return No; + + // real time processes shouldn't wait that much. + if (process.Affinity == AffinityKind::kRealTime) return Yes; + + return process.PTime < 1; +} + +/***********************************************************************************/ +/** + * @brief Start scheduling current AP. + */ +/***********************************************************************************/ + +SizeT UserProcessHelper::StartScheduling() { + return kScheduler.Run(); +} + +/***********************************************************************************/ +/** + * \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, UInt8* stack, HAL::StackFramePtr frame_ptr, + PID new_pid) { + for (SizeT index = 0UL; index < HardwareThreadScheduler::The().Capacity(); ++index) { + if (HardwareThreadScheduler::The()[index].Leak()->Kind() == kAPInvalid || + HardwareThreadScheduler::The()[index].Leak()->Kind() == kAPBoot) + continue; + + // A fallback is a special core for real-time tasks which needs immediate execution. + if (HardwareThreadScheduler::The()[index].Leak()->Kind() == kAPRealTime) { + if (UserProcessScheduler::The().CurrentTeam().AsArray()[new_pid].Affinity != + AffinityKind::kRealTime) + continue; + + if (HardwareThreadScheduler::The()[index].Leak()->Switch(image, stack, frame_ptr, new_pid)) { + HardwareThreadScheduler::The()[index].Leak()->fPTime = + UserProcessScheduler::The().CurrentTeam().AsArray()[new_pid].PTime; + + UserProcessHelper::TheCurrentPID().Leak().Leak() = UserProcessHelper::TheCurrentPID(); + + return YES; + } + + continue; + } + + if (UserProcessScheduler::The().CurrentTeam().AsArray()[new_pid].Affinity == + AffinityKind::kRealTime) + continue; + + //////////////////////////////////////////////////////////// + /// Prepare task switch. /// + //////////////////////////////////////////////////////////// + + Bool ret = + HardwareThreadScheduler::The()[index].Leak()->Switch(image, stack, frame_ptr, new_pid); - HAL::mm_map_page((VoidPtr)process.StackReserve, process.StackReserve, flags); -#endif // ifdef __NE_VIRTUAL_MEMORY_SUPPORT__ + //////////////////////////////////////////////////////////// + /// Rollback on fail. /// + //////////////////////////////////////////////////////////// - process.ProcessParentTeam = &mTeam; + if (!ret) continue; - process.ProcessId = pid; - process.Status = ProcessStatusKind::kStarting; - process.PTime = (UIntPtr)AffinityKind::kStandard; + UserProcessHelper::TheCurrentPID().Leak().Leak() = new_pid; - (void)(kout << "PID: " << number(process.ProcessId) << kendl); - (void)(kout << "Name: " << process.Name << kendl); + HardwareThreadScheduler::The()[index].Leak()->fPTime = + UserProcessScheduler::The().CurrentTeam().AsArray()[new_pid].PTime; + HardwareThreadScheduler::The()[index].Leak()->Wake(YES); - return pid; - } + return Yes; + } - /***********************************************************************************/ - /// @brief Retrieves the singleton of the process scheduler. - /***********************************************************************************/ + return No; +} - UserProcessScheduler& UserProcessScheduler::The() - { - return kProcessScheduler; - } - - /***********************************************************************************/ +//////////////////////////////////////////////////////////// +/// @brief this checks if any process is on the team. +//////////////////////////////////////////////////////////// +UserProcessScheduler::operator bool() { + return mTeam.AsArray().Count() > 0; +} - /// @brief Remove process from the team. - /// @param process_id process slot inside team. - /// @retval true process was removed. - /// @retval false process doesn't exist in team. - - /***********************************************************************************/ - - Void UserProcessScheduler::Remove(ProcessID process_id) - { - mTeam.mProcessList[process_id].Exit(0); - } - - /// @brief Is it a user scheduler? - - Bool UserProcessScheduler::IsUser() - { - return Yes; - } - - /// @brief Is it a kernel scheduler? - - Bool UserProcessScheduler::IsKernel() - { - return No; - } - - /// @brief Is it a SMP scheduler? - - Bool UserProcessScheduler::HasMP() - { - return Yes; - } - - /***********************************************************************************/ - /// @brief Run User scheduler object. - /// @return Process count executed within a team. - /***********************************************************************************/ - - SizeT UserProcessScheduler::Run() noexcept - { - SizeT process_index = 0UL; //! we store this guy to tell the scheduler how many - //! things we have scheduled. - - if (mTeam.mProcessCount < 1) - { - return 0UL; - } - - for (; process_index < mTeam.AsArray().Capacity(); ++process_index) - { - auto& process = mTeam.AsArray()[process_index]; - - //! check if the process needs to be run. - if (UserProcessHelper::CanBeScheduled(process)) - { - // Set current process header. - this->CurrentProcess() = process; - - process.PTime = static_cast<Int32>(process.Affinity); - - // tell helper to find a core to schedule on. - BOOL ret = UserProcessHelper::Switch(process.Image.fCode, &process.StackReserve[process.StackSize - 1], process.StackFrame, - process.ProcessId); - - if (!ret) - { - if (process.Affinity == AffinityKind::kRealTime) - continue; - - kout << "The process: " << process.Name << ", is not valid! Crashing it...\r"; - - process.Crash(); - } - } - else - { - --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<Process>& UserProcessScheduler::CurrentProcess() - { - return mTeam.AsRef(); - } - - /// @brief Current proccess id getter. - /// @return Process ID integer. - ErrorOr<PID> UserProcessHelper::TheCurrentPID() - { - if (!kProcessScheduler.CurrentProcess()) - return ErrorOr<PID>{kErrorProcessFault}; - - kout << "UserProcessHelper::TheCurrentPID: Leaking ProcessId...\r"; - return ErrorOr<PID>{kProcessScheduler.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 Process& process) - { - if (process.Status == ProcessStatusKind::kKilled || - process.Status == ProcessStatusKind::kFinished || - process.Status == ProcessStatusKind::kStarting || - process.Status == ProcessStatusKind::kFrozen) - return No; - - if (process.Status == ProcessStatusKind::kInvalid) - return No; - - if (!process.Image.fCode) - return No; - - if (!process.Name[0]) - return No; - - // real time processes shouldn't wait that much. - if (process.Affinity == AffinityKind::kRealTime) - return Yes; - - return process.PTime < 1; - } - - /***********************************************************************************/ - /** - * @brief Start scheduling current AP. - */ - /***********************************************************************************/ - - SizeT UserProcessHelper::StartScheduling() - { - return kProcessScheduler.Run(); - } - - /***********************************************************************************/ - /** - * \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, UInt8* stack, HAL::StackFramePtr frame_ptr, PID new_pid) - { - for (SizeT index = 0UL; index < HardwareThreadScheduler::The().Capacity(); ++index) - { - if (HardwareThreadScheduler::The()[index].Leak()->Kind() == kAPInvalid || - HardwareThreadScheduler::The()[index].Leak()->Kind() == kAPBoot) - continue; - - // A fallback is a special core for real-time tasks which needs immediate execution. - if (HardwareThreadScheduler::The()[index].Leak()->Kind() == kAPRealTime) - { - if (UserProcessScheduler::The().CurrentTeam().AsArray()[new_pid].Affinity != AffinityKind::kRealTime) - continue; - - if (HardwareThreadScheduler::The()[index].Leak()->Switch(image, stack, frame_ptr, new_pid)) - { - HardwareThreadScheduler::The()[index].Leak()->fPTime = UserProcessScheduler::The().CurrentTeam().AsArray()[new_pid].PTime; - - UserProcessHelper::TheCurrentPID().Leak().Leak() = UserProcessHelper::TheCurrentPID(); - - return YES; - } - - continue; - } - - if (UserProcessScheduler::The().CurrentTeam().AsArray()[new_pid].Affinity == AffinityKind::kRealTime) - continue; - - //////////////////////////////////////////////////////////// - /// Prepare task switch. /// - //////////////////////////////////////////////////////////// - - Bool ret = HardwareThreadScheduler::The()[index].Leak()->Switch(image, stack, frame_ptr, new_pid); - - //////////////////////////////////////////////////////////// - /// Rollback on fail. /// - //////////////////////////////////////////////////////////// - - if (!ret) - continue; - - UserProcessHelper::TheCurrentPID().Leak().Leak() = new_pid; - - HardwareThreadScheduler::The()[index].Leak()->fPTime = UserProcessScheduler::The().CurrentTeam().AsArray()[new_pid].PTime; - HardwareThreadScheduler::The()[index].Leak()->Wake(YES); - - return Yes; - } - - return No; - } - - //////////////////////////////////////////////////////////// - /// @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 +//////////////////////////////////////////////////////////// +/// @brief this checks if no process is on the team. +//////////////////////////////////////////////////////////// +Bool UserProcessScheduler::operator!() { + return mTeam.AsArray().Count() == 0; +} +} // namespace Kernel |
