diff --git a/include/scheduler.hpp b/include/scheduler.hpp
new file mode 100644
index 0000000..b23aa0b
--- /dev/null
+++ b/include/scheduler.hpp
@@ -0,0 +1,150 @@
+/*
+ This file is part of Fennix Kernel.
+
+ Fennix Kernel is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Kernel is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Kernel. If not, see .
+*/
+
+#pragma once
+
+#include
+#include
+
+namespace Tasking::Scheduler
+{
+ class Base
+ {
+ public:
+ Task *ctx = nullptr;
+ std::atomic_size_t SchedulerTicks = 0;
+ std::atomic_size_t LastTaskTicks = 0;
+ std::atomic_int LastCore = 0;
+ std::atomic_bool StopScheduler = false;
+ std::atomic_bool SchedulerUpdateTrapFrame = false;
+
+ /**
+ * Remove a thread from the scheduler
+ *
+ * @note This function is NOT thread safe
+ * @note This function does not check if
+ * the thread is valid nor if it has
+ * Terminated status
+ */
+ virtual bool RemoveThread(TCB *tcb)
+ {
+ assert(!"RemoveThread not implemented");
+ };
+
+ /**
+ * @note This function is NOT thread safe
+ */
+ virtual bool RemoveProcess(PCB *pcb)
+ {
+ assert(!"RemoveProcess not implemented");
+ }
+
+ virtual PCB *GetProcessByID(TID ID)
+ {
+ assert(!"GetProcessByID not implemented");
+ }
+
+ virtual TCB *GetThreadByID(TID ID)
+ {
+ assert(!"GetThreadByID not implemented");
+ }
+
+ virtual std::list &GetProcessList()
+ {
+ assert(!"GetProcessList not implemented");
+ }
+
+ virtual void StartIdleProcess()
+ {
+ assert(!"StartIdleProcess not implemented");
+ }
+
+ virtual void StartScheduler()
+ {
+ assert(!"StartScheduler not implemented");
+ }
+
+ virtual void Yield()
+ {
+ assert(!"Yield not implemented");
+ }
+
+ virtual void PushProcess(PCB *pcb)
+ {
+ assert(!"PushProcess not implemented");
+ }
+
+ virtual void PopProcess(PCB *pcb)
+ {
+ assert(!"PopProcess not implemented");
+ }
+
+ Base(Task *_ctx)
+ : ctx(_ctx) {}
+
+ ~Base() {}
+ };
+
+ class Custom : public Base,
+ public Interrupts::Handler
+ {
+ private:
+ NewLock(SchedulerLock);
+
+ public:
+ std::list ProcessList;
+
+ PCB *IdleProcess = nullptr;
+ TCB *IdleThread = nullptr;
+
+ bool RemoveThread(TCB *tcb) final;
+ bool RemoveProcess(PCB *pcb) final;
+ PCB *GetProcessByID(TID ID) final;
+ TCB *GetThreadByID(TID ID) final;
+ std::list &GetProcessList() final;
+ void StartIdleProcess() final;
+ void StartScheduler() final;
+ void Yield() final;
+ void PushProcess(PCB *pcb) final;
+ void PopProcess(PCB *pcb) final;
+
+ void OneShot(int TimeSlice);
+
+ void UpdateUsage(TaskInfo *Info,
+ TaskExecutionMode Mode,
+ int Core);
+
+ bool FindNewProcess(void *CPUDataPointer);
+ bool GetNextAvailableThread(void *CPUDataPointer);
+ bool GetNextAvailableProcess(void *CPUDataPointer);
+ bool SchedulerSearchProcessThread(void *CPUDataPointer);
+ void UpdateProcessState();
+ void WakeUpThreads();
+ void CleanupTerminated();
+
+ void Schedule(CPU::TrapFrame *Frame);
+ void OnInterruptReceived(CPU::TrapFrame *Frame) final;
+
+ Custom(Task *ctx);
+ virtual ~Custom();
+ };
+
+ class RoundRobin : public Base,
+ public Interrupts::Handler
+ {
+ };
+}
diff --git a/include/task.hpp b/include/task.hpp
index 22dd91c..d6835d6 100644
--- a/include/task.hpp
+++ b/include/task.hpp
@@ -467,7 +467,7 @@ namespace Tasking
~PCB();
};
- class Task : public Interrupts::Handler
+ class Task
{
private:
NewLock(SchedulerLock);
@@ -476,114 +476,43 @@ namespace Tasking
PID NextPID = 0;
TID NextTID = 0;
- std::list ProcessList;
PCB *KernelProcess = nullptr;
- PCB *IdleProcess = nullptr;
- TCB *IdleThread = nullptr;
- std::atomic_size_t SchedulerTicks = 0;
- std::atomic_size_t LastTaskTicks = 0;
- std::atomic_int LastCore = 0;
- std::atomic_bool StopScheduler = false;
- std::atomic_bool SchedulerUpdateTrapFrame = false;
- bool InvalidPCB(PCB *pcb);
- bool InvalidTCB(TCB *tcb);
+ void *Scheduler = nullptr;
+ void *__sched_ctx = nullptr;
- /**
- * Remove a thread from the scheduler
- *
- * @note This function is NOT thread safe
- * @note This function does not check if
- * the thread is valid nor if it has
- * Terminated status
- */
- bool RemoveThread(TCB *tcb);
+ constexpr TaskArchitecture GetKArch()
+ {
+#if defined(a64)
+ return x64;
+#elif defined(a32)
+ return x32;
+#elif defined(aa64)
+ return ARM64;
+#endif
+ }
- /**
- * @note This function is NOT thread safe
- */
- bool RemoveProcess(PCB *pcb);
-
- void UpdateUsage(TaskInfo *Info,
- TaskExecutionMode Mode,
- int Core);
-
- /**
- * @note This function is NOT thread safe
- */
- bool FindNewProcess(void *CPUDataPointer);
-
- /**
- * @note This function is NOT thread safe
- */
- bool GetNextAvailableThread(void *CPUDataPointer);
-
- /**
- * @note This function is NOT thread safe
- */
- bool GetNextAvailableProcess(void *CPUDataPointer);
-
- /**
- * @note This function is NOT thread safe
- */
- bool SchedulerSearchProcessThread(void *CPUDataPointer);
-
- /**
- * @note This function is NOT thread safe
- */
- void UpdateProcessState();
-
- /**
- * @note This function is NOT thread safe
- */
- void WakeUpThreads();
-
- /**
- * @note This function is NOT thread safe
- */
- void CleanupTerminated();
-
- /**
- * @note This function is NOT thread safe
- */
- void Schedule(CPU::TrapFrame *Frame);
-
- void OnInterruptReceived(CPU::TrapFrame *Frame) final;
+ void PushProcess(PCB *pcb);
+ void PopProcess(PCB *pcb);
public:
+ void *GetScheduler() { return Scheduler; }
PCB *GetKernelProcess() { return KernelProcess; }
- size_t GetSchedulerTicks() { return SchedulerTicks.load(); }
- size_t GetLastTaskTicks() { return LastTaskTicks.load(); }
- int GetLastCore() { return LastCore.load(); }
- std::list GetProcessList() { return ProcessList; }
- void Panic() { StopScheduler = true; }
- bool IsPanic() { return StopScheduler; }
+ std::list GetProcessList();
+ void Panic();
+ bool IsPanic();
/**
* Yield the current thread and switch
* to another thread if available
*/
- __always_inline inline void Yield()
- {
- /* This will trigger the IRQ16
- instantly so we won't execute
- the next instruction */
-#if defined(a86)
- asmv("int $0x30");
-#elif defined(aa64)
- asmv("svc #0x30");
-#endif
- }
+ void Yield();
/**
* Update the current thread's trap frame
* without switching to another thread
*/
- __always_inline inline void UpdateFrame()
- {
- SchedulerUpdateTrapFrame = true;
- Yield();
- }
+ void UpdateFrame();
void SignalShutdown();
@@ -670,6 +599,4 @@ namespace Tasking
#define thisProcess GetCurrentCPU()->CurrentProcess.load()
#define thisThread GetCurrentCPU()->CurrentThread.load()
-extern "C" void TaskingScheduler_OneShot(int TimeSlice);
-
#endif // !__FENNIX_KERNEL_TASKING_H__
diff --git a/tasking/process.cpp b/tasking/process.cpp
index 7d331b4..734252e 100644
--- a/tasking/process.cpp
+++ b/tasking/process.cpp
@@ -228,7 +228,7 @@ namespace Tasking
if (Parent)
Parent->Children.push_back(this);
- ctx->ProcessList.push_back(this);
+ ctx->PushProcess(this);
}
PCB::~PCB()
@@ -240,9 +240,7 @@ namespace Tasking
debug("Removing from process list");
/* Remove us from the process list so we
don't get scheduled anymore */
- ctx->ProcessList.erase(std::find(ctx->ProcessList.begin(),
- ctx->ProcessList.end(),
- this));
+ ctx->PopProcess(this);
debug("Freeing signals");
delete this->Signals;
diff --git a/tasking/scheduler.cpp b/tasking/scheduler/custom.cpp
similarity index 73%
rename from tasking/scheduler.cpp
rename to tasking/scheduler/custom.cpp
index 933c5df..f224fd2 100644
--- a/tasking/scheduler.cpp
+++ b/tasking/scheduler/custom.cpp
@@ -15,7 +15,7 @@
along with Fennix Kernel. If not, see .
*/
-#include
+#include
#include
#include
@@ -103,26 +103,187 @@
#define wut_schedbg(m, ...)
#endif
-extern "C" nsa NIF void TaskingScheduler_OneShot(int TimeSlice)
+__naked __used nsa void __custom_sched_idle_loop()
{
- if (TimeSlice == 0)
- TimeSlice = Tasking::TaskPriority::Normal;
-
-#ifdef DEBUG
- if (DebuggerIsAttached)
- TimeSlice += 10;
-#endif
-
#if defined(a86)
- ((APIC::Timer *)Interrupts::apicTimer[GetCurrentCPU()->ID])->OneShot(CPU::x86::IRQ16, TimeSlice);
+ asmv("IdleLoop:");
+ asmv("hlt");
+ asmv("jmp IdleLoop");
#elif defined(aa64)
+ asmv("IdleLoop:");
+ asmv("wfe");
+ asmv("b IdleLoop");
#endif
}
-namespace Tasking
+namespace Tasking::Scheduler
{
+ bool Custom::RemoveThread(TCB *Thread)
+ {
+ debug("Thread \"%s\"(%d) removed from process \"%s\"(%d)",
+ Thread->Name, Thread->ID, Thread->Parent->Name,
+ Thread->Parent->ID);
+
+ delete Thread;
+ return true;
+ }
+
+ bool Custom::RemoveProcess(PCB *Process)
+ {
+ if (Process->State == Terminated)
+ {
+ delete Process;
+ return true;
+ }
+
+ foreach (TCB *Thread in Process->Threads)
+ {
+ if (Thread->State == Terminated)
+ RemoveThread(Thread);
+ }
+
+ return true;
+ }
+
+ PCB *Custom::GetProcessByID(TID ID)
+ {
+ foreach (auto p in ProcessList)
+ {
+ if (p->ID == ID)
+ return p;
+ }
+ return nullptr;
+ }
+
+ TCB *Custom::GetThreadByID(TID ID)
+ {
+ foreach (auto p in ProcessList)
+ {
+ foreach (auto t in p->Threads)
+ {
+ if (t->ID == ID)
+ return t;
+ }
+ }
+ return nullptr;
+ }
+
+ void Custom::StartIdleProcess()
+ {
+ IdleProcess = ctx->CreateProcess(nullptr, (char *)"Idle",
+ TaskExecutionMode::Kernel, true);
+ for (int i = 0; i < SMP::CPUCores; i++)
+ {
+ TCB *thd = ctx->CreateThread(IdleProcess, IP(__custom_sched_idle_loop));
+ char IdleName[16];
+ sprintf(IdleName, "Idle Thread %d", i);
+ thd->Rename(IdleName);
+ thd->SetPriority(Idle);
+ for (int j = 0; j < MAX_CPU; j++)
+ thd->Info.Affinity[j] = false;
+ thd->Info.Affinity[i] = true;
+
+ if (unlikely(i == 0))
+ IdleThread = thd;
+ }
+ }
+
+ std::list &Custom::GetProcessList()
+ {
+ return ProcessList;
+ }
+
+ void Custom::StartScheduler()
+ {
#if defined(a86)
- nsa NIF bool Task::FindNewProcess(void *CPUDataPointer)
+ if (Interrupts::apicTimer[0])
+ {
+ ((APIC::Timer *)Interrupts::apicTimer[0])->OneShot(CPU::x86::IRQ16, 100);
+
+ /* FIXME: The kernel is not ready for multi-core tasking. */
+ return;
+
+ APIC::InterruptCommandRegister icr{};
+ bool x2APIC = ((APIC::APIC *)Interrupts::apic[0])->x2APIC;
+
+ if (likely(x2APIC))
+ {
+ icr.x2.VEC = s_cst(uint8_t, CPU::x86::IRQ16);
+ icr.x2.MT = APIC::Fixed;
+ icr.x2.L = APIC::Assert;
+ icr.x2.DES = 0xFFFFFFFF; /* Broadcast IPI to all local APICs. */
+ ((APIC::APIC *)Interrupts::apic[0])->ICR(icr);
+ }
+ else
+ {
+ icr.VEC = s_cst(uint8_t, CPU::x86::IRQ16);
+ icr.MT = APIC::Fixed;
+ icr.L = APIC::Assert;
+
+ for (int i = 0; i < SMP::CPUCores; i++)
+ {
+ icr.DES = uint8_t(i);
+ ((APIC::APIC *)Interrupts::apic[i])->ICR(icr);
+ }
+ }
+ }
+#endif
+ }
+
+ void Custom::Yield()
+ {
+ /* This will trigger the IRQ16
+ instantly so we won't execute
+ the next instruction */
+#if defined(a86)
+ asmv("int $0x30");
+#elif defined(aa64)
+ asmv("svc #0x30");
+#endif
+ }
+
+ void Custom::PushProcess(PCB *pcb)
+ {
+ this->ProcessList.push_back(pcb);
+ }
+
+ void Custom::PopProcess(PCB *pcb)
+ {
+ this->ProcessList.remove(pcb);
+ }
+
+ /* --------------------------------------------------------------- */
+
+ nsa void Custom::OneShot(int TimeSlice)
+ {
+ if (TimeSlice == 0)
+ TimeSlice = Tasking::TaskPriority::Normal;
+
+#ifdef DEBUG
+ if (DebuggerIsAttached)
+ TimeSlice += 10;
+#endif
+
+#if defined(a86)
+ ((APIC::Timer *)Interrupts::apicTimer[GetCurrentCPU()->ID])->OneShot(CPU::x86::IRQ16, TimeSlice);
+#elif defined(aa64)
+#endif
+ }
+
+ nsa void Custom::UpdateUsage(TaskInfo *Info, TaskExecutionMode Mode, int Core)
+ {
+ UNUSED(Core);
+ uint64_t CurrentTime = TimeManager->GetCounter();
+ uint64_t TimePassed = Info->LastUpdateTime - CurrentTime;
+ Info->LastUpdateTime = CurrentTime;
+
+ if (Mode == TaskExecutionMode::User)
+ Info->UserTime += TimePassed;
+ else
+ Info->KernelTime += TimePassed;
+ }
+
+ nsa NIF bool Custom::FindNewProcess(void *CPUDataPointer)
{
CPUData *CurrentCPU = (CPUData *)CPUDataPointer;
fnp_schedbg("%d processes", ProcessList.size());
@@ -133,9 +294,6 @@ namespace Tasking
#endif
foreach (auto process in ProcessList)
{
- if (unlikely(InvalidPCB(process)))
- continue;
-
switch (process->State.load())
{
case TaskState::Ready:
@@ -157,9 +315,6 @@ namespace Tasking
foreach (auto thread in process->Threads)
{
- if (unlikely(InvalidTCB(thread)))
- continue;
-
if (thread->State.load() != TaskState::Ready)
continue;
@@ -175,7 +330,7 @@ namespace Tasking
return false;
}
- nsa NIF bool Task::GetNextAvailableThread(void *CPUDataPointer)
+ nsa NIF bool Custom::GetNextAvailableThread(void *CPUDataPointer)
{
CPUData *CurrentCPU = (CPUData *)CPUDataPointer;
@@ -192,16 +347,6 @@ namespace Tasking
TCB *nextThread = CurrentCPU->CurrentProcess->Threads[TempIndex + 1];
- if (unlikely(InvalidTCB(nextThread)))
- {
- if (TempIndex > ThreadsSize)
- break;
- TempIndex++;
-
- gnat_schedbg("Thread %#lx is invalid", nextThread);
- goto RetryAnotherThread;
- }
-
gnat_schedbg("\"%s\"(%d) and next thread is \"%s\"(%d)",
CurrentCPU->CurrentProcess->Threads[i]->Name,
CurrentCPU->CurrentProcess->Threads[i]->ID,
@@ -234,7 +379,7 @@ namespace Tasking
return false;
}
- nsa NIF bool Task::GetNextAvailableProcess(void *CPUDataPointer)
+ nsa NIF bool Custom::GetNextAvailableProcess(void *CPUDataPointer)
{
CPUData *CurrentCPU = (CPUData *)CPUDataPointer;
@@ -254,12 +399,6 @@ namespace Tasking
continue;
}
- if (unlikely(InvalidPCB(process)))
- {
- gnap_schedbg("Invalid process %#lx", process);
- continue;
- }
-
if (process->State.load() != TaskState::Ready)
{
gnap_schedbg("Process %d is not ready", process->ID);
@@ -268,12 +407,6 @@ namespace Tasking
foreach (auto thread in process->Threads)
{
- if (unlikely(InvalidTCB(thread)))
- {
- gnap_schedbg("Invalid thread %#lx", thread);
- continue;
- }
-
if (thread->State.load() != TaskState::Ready)
{
gnap_schedbg("Thread %d is not ready", thread->ID);
@@ -294,18 +427,12 @@ namespace Tasking
return false;
}
- nsa NIF bool Task::SchedulerSearchProcessThread(void *CPUDataPointer)
+ nsa NIF bool Custom::SchedulerSearchProcessThread(void *CPUDataPointer)
{
CPUData *CurrentCPU = (CPUData *)CPUDataPointer;
foreach (auto process in ProcessList)
{
- if (unlikely(InvalidPCB(process)))
- {
- sspt_schedbg("Invalid process %#lx", process);
- continue;
- }
-
if (process->State.load() != TaskState::Ready)
{
sspt_schedbg("Process %d is not ready", process->ID);
@@ -314,12 +441,6 @@ namespace Tasking
foreach (auto thread in process->Threads)
{
- if (unlikely(InvalidTCB(thread)))
- {
- sspt_schedbg("Invalid thread %#lx", thread);
- continue;
- }
-
if (thread->State.load() != TaskState::Ready)
{
sspt_schedbg("Thread %d is not ready", thread->ID);
@@ -339,13 +460,10 @@ namespace Tasking
return false;
}
- nsa NIF void Task::UpdateProcessState()
+ nsa NIF void Custom::UpdateProcessState()
{
foreach (auto process in ProcessList)
{
- if (unlikely(InvalidPCB(process)))
- continue;
-
if (process->State.load() == TaskState::Terminated)
continue;
@@ -375,13 +493,10 @@ namespace Tasking
}
}
- nsa NIF void Task::WakeUpThreads()
+ nsa NIF void Custom::WakeUpThreads()
{
foreach (auto process in ProcessList)
{
- if (unlikely(InvalidPCB(process)))
- continue;
-
Tasking::TaskState pState = process->State.load();
if (pState != TaskState::Ready &&
pState != TaskState::Sleeping &&
@@ -390,9 +505,6 @@ namespace Tasking
foreach (auto thread in process->Threads)
{
- if (unlikely(InvalidTCB(thread)))
- continue;
-
if (likely(thread->State.load() != TaskState::Sleeping))
continue;
@@ -415,7 +527,7 @@ namespace Tasking
}
}
- nsa NIF void Task::CleanupTerminated()
+ nsa NIF void Custom::CleanupTerminated()
{
foreach (auto pcb in ProcessList)
{
@@ -433,7 +545,7 @@ namespace Tasking
}
}
- nsa NIF void Task::Schedule(CPU::TrapFrame *Frame)
+ nsa NIF void Custom::Schedule(CPU::TrapFrame *Frame)
{
if (unlikely(StopScheduler))
{
@@ -450,8 +562,8 @@ namespace Tasking
this->LastCore.store(CurrentCPU->ID);
schedbg("Scheduler called on CPU %d.", CurrentCPU->ID);
- if (unlikely(InvalidPCB(CurrentCPU->CurrentProcess.load()) ||
- InvalidTCB(CurrentCPU->CurrentThread.load())))
+ if (unlikely(!CurrentCPU->CurrentProcess.load() ||
+ !CurrentCPU->CurrentThread.load()))
{
schedbg("Invalid process or thread. Finding a new one.");
ProcessNotChanged = true;
@@ -524,9 +636,7 @@ namespace Tasking
}
}
- warn("Unwanted reach!");
- TaskingScheduler_OneShot(100);
- goto End;
+ assert(!"Unwanted code execution");
Idle:
ProcessNotChanged = true;
@@ -586,7 +696,7 @@ namespace Tasking
if (!ProcessNotChanged)
(&CurrentCPU->CurrentProcess->Info)->LastUpdateTime = TimeManager->GetCounter();
(&CurrentCPU->CurrentThread->Info)->LastUpdateTime = TimeManager->GetCounter();
- TaskingScheduler_OneShot(CurrentCPU->CurrentThread->Info.Priority);
+ this->OneShot(CurrentCPU->CurrentThread->Info.Priority);
if (CurrentCPU->CurrentThread->Security.IsDebugEnabled &&
CurrentCPU->CurrentThread->Security.IsKernelDebugEnabled)
@@ -627,42 +737,74 @@ namespace Tasking
Frame->rip, Frame->rflags, Frame->InterruptNumber, Frame->ErrorCode);
schedbg("================================================================");
- End:
this->SchedulerTicks.store(size_t(TimeManager->GetCounter() - SchedTmpTicks));
CurrentCPU->CurrentProcess->PageTable->Update();
}
- nsa NIF void Task::OnInterruptReceived(CPU::TrapFrame *Frame)
+ nsa NIF void Custom::OnInterruptReceived(CPU::TrapFrame *Frame)
{
SmartCriticalSection(SchedulerLock);
this->Schedule(Frame);
}
-#elif defined(aa64)
- nsa bool Task::FindNewProcess(void *CPUDataPointer)
- {
- fixme("unimplemented");
- }
- nsa bool Task::GetNextAvailableThread(void *CPUDataPointer)
+ Custom::Custom(Task *ctx) : Base(ctx), Interrupts::Handler(16) /* IRQ16 */
{
- fixme("unimplemented");
- }
-
- nsa bool Task::GetNextAvailableProcess(void *CPUDataPointer)
- {
- fixme("unimplemented");
- }
-
- nsa bool Task::SchedulerSearchProcessThread(void *CPUDataPointer)
- {
- fixme("unimplemented");
- }
-
- nsa void Task::Schedule(CPU::TrapFrame *Frame)
- {
- fixme("unimplemented");
- }
-
- nsa void Task::OnInterruptReceived(CPU::TrapFrame *Frame) { this->Schedule(Frame); }
+#if defined(a86)
+ // Map the IRQ16 to the first CPU.
+ ((APIC::APIC *)Interrupts::apic[0])->RedirectIRQ(0, CPU::x86::IRQ16 - CPU::x86::IRQ0, 1);
#endif
+ }
+
+ Custom::~Custom()
+ {
+ foreach (PCB *Process in ProcessList)
+ {
+ foreach (TCB *Thread in Process->Threads)
+ {
+ if (Thread == GetCurrentCPU()->CurrentThread.load())
+ continue;
+ ctx->KillThread(Thread, KILL_SCHEDULER_DESTRUCTION);
+ }
+
+ if (Process == GetCurrentCPU()->CurrentProcess.load())
+ continue;
+ ctx->KillProcess(Process, KILL_SCHEDULER_DESTRUCTION);
+ }
+
+ debug("Waiting for processes to terminate");
+ uint64_t timeout = TimeManager->CalculateTarget(20, Time::Units::Seconds);
+ while (this->GetProcessList().size() > 0)
+ {
+ trace("Waiting for %d processes to terminate", this->GetProcessList().size());
+ int NotTerminated = 0;
+ foreach (PCB *Process in this->GetProcessList())
+ {
+ trace("Process %s(%d) is still running (or waiting to be removed state %#lx)",
+ Process->Name, Process->ID, Process->State);
+
+ if (Process->State == TaskState::Terminated)
+ {
+ debug("Process %s(%d) terminated", Process->Name, Process->ID);
+ continue;
+ }
+
+ NotTerminated++;
+ }
+ if (NotTerminated == 1)
+ break;
+
+ ctx->Sleep(1000);
+ debug("Current working process is %s(%d)",
+ ctx->GetCurrentProcess()->Name,
+ ctx->GetCurrentProcess()->ID);
+
+ if (TimeManager->GetCounter() > timeout)
+ {
+ error("Timeout waiting for processes to terminate");
+ break;
+ }
+
+ this->OneShot(100);
+ }
+ }
}
diff --git a/tasking/task.cpp b/tasking/task.cpp
index 94acafd..808d242 100644
--- a/tasking/task.cpp
+++ b/tasking/task.cpp
@@ -17,6 +17,7 @@
#include
+#include
#include
#include
#include
@@ -46,104 +47,6 @@
namespace Tasking
{
-#if defined(a86)
- __naked __used __no_stack_protector void IdleProcessLoop()
- {
- asmv("IdleLoop:");
- asmv("hlt");
- asmv("jmp IdleLoop");
-#elif defined(aa64)
- __used __no_stack_protector void IdleProcessLoop()
- {
- asmv("IdleLoop:");
- asmv("wfe");
- asmv("b IdleLoop");
-#endif
- }
-
- nsa bool Task::InvalidPCB(PCB *pcb)
- {
- if (!pcb)
- return true;
-
- /* Uninitialized pointers may have uintptr_t max value instead of nullptr. */
- if (pcb >= (PCB *)(UINTPTR_MAX - 0x1FFE))
- return true;
-
- /* In this section of the memory is reserved by the kernel. */
- if (pcb < (PCB *)(0xFFFFF))
- return true;
-
- /* Check if it's mapped. */
- if (!Memory::Virtual().Check((void *)pcb))
- return true;
-
- return false;
- }
-
- nsa bool Task::InvalidTCB(TCB *tcb)
- {
- if (!tcb)
- return true;
-
- /* Uninitialized pointers may have uintptr_t max value instead of nullptr. */
- if (tcb >= (TCB *)(UINTPTR_MAX - 0x1FFE))
- return true;
-
- /* In this section of the memory is reserved by the kernel. */
- if (tcb < (TCB *)(0xFFFFF))
- return true;
-
- /* Check if it's mapped. */
- if (!Memory::Virtual().Check((void *)tcb))
- return true;
-
- return false;
- }
-
- nsa bool Task::RemoveThread(TCB *Thread)
- {
- debug("Thread \"%s\"(%d) removed from process \"%s\"(%d)",
- Thread->Name, Thread->ID, Thread->Parent->Name,
- Thread->Parent->ID);
-
- delete Thread;
- return true;
- }
-
- nsa bool Task::RemoveProcess(PCB *Process)
- {
- if (unlikely(InvalidPCB(Process)))
- return false;
-
- if (Process->State == Terminated)
- {
- delete Process;
- return true;
- }
-
- foreach (TCB *Thread in Process->Threads)
- {
- if (Thread->State == Terminated)
- RemoveThread(Thread);
- }
-
- return true;
- }
-
- nsa void Task::UpdateUsage(TaskInfo *Info, TaskExecutionMode Mode, int Core)
- {
- UNUSED(Core);
- uint64_t CurrentTime = TimeManager->GetCounter();
- uint64_t TimePassed = CurrentTime - Info->LastUpdateTime;
- // Info->LastUpdateTime = CurrentTime;
-
- if (Mode == TaskExecutionMode::User)
- Info->UserTime += TimePassed;
- else
- Info->KernelTime += TimePassed;
- }
-
PCB *Task::GetCurrentProcess()
{
return GetCurrentCPU()->CurrentProcess.load();
@@ -156,34 +59,52 @@ namespace Tasking
PCB *Task::GetProcessByID(TID ID)
{
- SmartLock(TaskingLock);
- foreach (auto p in ProcessList)
- {
- if (p->ID == ID)
- return p;
- }
- return nullptr;
+ return ((Scheduler::Base *)Scheduler)->GetProcessByID(ID);
}
TCB *Task::GetThreadByID(TID ID)
{
- SmartLock(TaskingLock);
- foreach (auto p in ProcessList)
- {
- foreach (auto t in p->Threads)
- {
- if (t->ID == ID)
- return t;
- }
- }
- return nullptr;
+ return ((Scheduler::Base *)Scheduler)->GetThreadByID(ID);
+ }
+
+ std::list Task::GetProcessList()
+ {
+ return ((Scheduler::Base *)Scheduler)->GetProcessList();
+ }
+
+ void Task::Panic()
+ {
+ ((Scheduler::Base *)Scheduler)->StopScheduler.store(true);
+ }
+
+ bool Task::IsPanic()
+ {
+ return ((Scheduler::Base *)Scheduler)->StopScheduler;
+ }
+
+ void Task::Yield()
+ {
+ ((Scheduler::Base *)Scheduler)->Yield();
+ }
+
+ void Task::UpdateFrame()
+ {
+ ((Scheduler::Base *)Scheduler)->SchedulerUpdateTrapFrame = true;
+ ((Scheduler::Base *)Scheduler)->Yield();
+ }
+
+ void Task::PushProcess(PCB *pcb)
+ {
+ ((Scheduler::Base *)Scheduler)->PushProcess(pcb);
+ }
+
+ void Task::PopProcess(PCB *pcb)
+ {
+ ((Scheduler::Base *)Scheduler)->PopProcess(pcb);
}
void Task::WaitForProcess(PCB *pcb)
{
- if (unlikely(InvalidPCB(pcb)))
- return;
-
if (pcb->State == TaskState::UnknownStatus)
return;
@@ -198,9 +119,6 @@ namespace Tasking
void Task::WaitForThread(TCB *tcb)
{
- if (unlikely(InvalidTCB(tcb)))
- return;
-
if (tcb->State == TaskState::UnknownStatus)
return;
@@ -215,9 +133,6 @@ namespace Tasking
void Task::WaitForProcessStatus(PCB *pcb, TaskState status)
{
- if (unlikely(InvalidPCB(pcb)))
- return;
-
if (pcb->State == TaskState::UnknownStatus)
return;
@@ -230,9 +145,6 @@ namespace Tasking
void Task::WaitForThreadStatus(TCB *tcb, TaskState status)
{
- if (unlikely(InvalidTCB(tcb)))
- return;
-
if (tcb->State == TaskState::UnknownStatus)
return;
@@ -277,7 +189,7 @@ namespace Tasking
GetCurrentProcess()->Name, GetCurrentProcess()->ID,
GetCurrentThread()->Name, GetCurrentThread()->ID);
- foreach (auto pcb in ProcessList)
+ foreach (auto pcb in((Scheduler::Base *)Scheduler)->GetProcessList())
{
if (pcb->State == TaskState::Terminated ||
pcb->State == TaskState::Zombie)
@@ -295,13 +207,10 @@ namespace Tasking
}
__no_sanitize("undefined")
- TCB *Task::CreateThread(PCB *Parent,
- IP EntryPoint,
- const char **argv,
- const char **envp,
+ TCB *Task::CreateThread(PCB *Parent, IP EntryPoint,
+ const char **argv, const char **envp,
const std::vector &auxv,
- TaskArchitecture arch,
- TaskCompatibility Compatibility,
+ TaskArchitecture arch, TaskCompatibility Compatibility,
bool ThreadNotReady)
{
SmartLock(TaskingLock);
@@ -310,10 +219,8 @@ namespace Tasking
Compatibility, ThreadNotReady);
}
- PCB *Task::CreateProcess(PCB *Parent,
- const char *Name,
- TaskExecutionMode ExecutionMode,
- bool UseKernelPageTable,
+ PCB *Task::CreateProcess(PCB *Parent, const char *Name,
+ TaskExecutionMode ExecutionMode, bool UseKernelPageTable,
uint16_t UserID, uint16_t GroupID)
{
SmartLock(TaskingLock);
@@ -323,169 +230,40 @@ namespace Tasking
void Task::StartScheduler()
{
-#if defined(a86)
- if (Interrupts::apicTimer[0])
- {
- ((APIC::Timer *)Interrupts::apicTimer[0])->OneShot(CPU::x86::IRQ16, 100);
-
- /* FIXME: The kernel is not ready for multi-core tasking. */
- return;
-
- APIC::InterruptCommandRegister icr{};
- bool x2APIC = ((APIC::APIC *)Interrupts::apic[0])->x2APIC;
-
- if (likely(x2APIC))
- {
- icr.x2.VEC = s_cst(uint8_t, CPU::x86::IRQ16);
- icr.x2.MT = APIC::Fixed;
- icr.x2.L = APIC::Assert;
- icr.x2.DES = 0xFFFFFFFF; /* Broadcast IPI to all local APICs. */
- ((APIC::APIC *)Interrupts::apic[0])->ICR(icr);
- }
- else
- {
- icr.VEC = s_cst(uint8_t, CPU::x86::IRQ16);
- icr.MT = APIC::Fixed;
- icr.L = APIC::Assert;
-
- for (int i = 0; i < SMP::CPUCores; i++)
- {
- icr.DES = uint8_t(i);
- ((APIC::APIC *)Interrupts::apic[i])->ICR(icr);
- }
- }
- }
-#elif defined(aa64)
-#endif
+ ((Scheduler::Base *)Scheduler)->StartScheduler();
debug("Tasking Started");
}
- Task::Task(const IP EntryPoint) : Interrupts::Handler(16) /* IRQ16 */
+ Task::Task(const IP EntryPoint)
{
-#if defined(a64)
- // Map the IRQ16 to the first CPU.
- ((APIC::APIC *)Interrupts::apic[0])->RedirectIRQ(0, CPU::x86::IRQ16 - CPU::x86::IRQ0, 1);
-#elif defined(a32)
-#elif defined(aa64)
-#endif
- KPrint("Starting tasking instance %#lx with ip: %p (\e666666%s\eCCCCCC)",
- this, EntryPoint, KernelSymbolTable->GetSymbol(EntryPoint));
-
-#if defined(a64)
- TaskArchitecture Arch = TaskArchitecture::x64;
-#elif defined(a32)
- TaskArchitecture Arch = TaskArchitecture::x32;
-#elif defined(aa64)
- TaskArchitecture Arch = TaskArchitecture::ARM64;
-#endif
+ /* I don't know if this is the best way to do this. */
+ Scheduler::Custom *custom_sched = new Scheduler::Custom(this);
+ Scheduler::Base *sched = r_cst(Scheduler::Base *, custom_sched);
+ __sched_ctx = custom_sched;
+ Scheduler = sched;
KernelProcess = CreateProcess(nullptr, "Kernel",
TaskExecutionMode::Kernel, true);
KernelProcess->PageTable = KernelPageTable;
TCB *kthrd = CreateThread(KernelProcess, EntryPoint,
nullptr, nullptr,
- std::vector(), Arch);
+ std::vector(), GetKArch());
kthrd->Rename("Main Thread");
debug("Created Kernel Process: %s and Thread: %s",
KernelProcess->Name, kthrd->Name);
- bool MONITORSupported = false;
- if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_AMD) == 0)
- {
- CPU::x86::AMD::CPUID0x00000001 cpuid;
- MONITORSupported = cpuid.ECX.MONITOR;
- }
- else if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_INTEL) == 0)
- {
- CPU::x86::Intel::CPUID0x00000001 cpuid;
- MONITORSupported = cpuid.ECX.MONITOR;
- }
-
- if (MONITORSupported)
- {
- trace("CPU has MONITOR/MWAIT support.");
- }
-
if (!CPU::Interrupts(CPU::Check))
{
error("Interrupts are not enabled.");
CPU::Interrupts(CPU::Enable);
}
- IdleProcess = CreateProcess(nullptr, (char *)"Idle",
- TaskExecutionMode::Kernel, true);
- for (int i = 0; i < SMP::CPUCores; i++)
- {
- TCB *thd = CreateThread(IdleProcess, IP(IdleProcessLoop));
- char IdleName[16];
- sprintf(IdleName, "Idle Thread %d", i);
- thd->Rename(IdleName);
- thd->SetPriority(Idle);
- for (int j = 0; j < MAX_CPU; j++)
- thd->Info.Affinity[j] = false;
- thd->Info.Affinity[i] = true;
-
- if (unlikely(i == 0))
- IdleThread = thd;
- }
+ ((Scheduler::Base *)Scheduler)->StartIdleProcess();
debug("Tasking is ready");
}
Task::~Task()
{
- debug("Destructor called");
- {
- SmartLock(TaskingLock);
- foreach (PCB *Process in ProcessList)
- {
- foreach (TCB *Thread in Process->Threads)
- {
- if (Thread == GetCurrentCPU()->CurrentThread.load())
- continue;
- this->KillThread(Thread, KILL_SCHEDULER_DESTRUCTION);
- }
-
- if (Process == GetCurrentCPU()->CurrentProcess.load())
- continue;
- this->KillProcess(Process, KILL_SCHEDULER_DESTRUCTION);
- }
- }
-
- debug("Waiting for processes to terminate");
- uint64_t timeout = TimeManager->CalculateTarget(20, Time::Units::Seconds);
- while (ProcessList.size() > 0)
- {
- trace("Waiting for %d processes to terminate", ProcessList.size());
- int NotTerminated = 0;
- foreach (PCB *Process in ProcessList)
- {
- trace("Process %s(%d) is still running (or waiting to be removed state %#lx)",
- Process->Name, Process->ID, Process->State);
-
- if (Process->State == TaskState::Terminated)
- {
- debug("Process %s(%d) terminated", Process->Name, Process->ID);
- continue;
- }
-
- NotTerminated++;
- }
- if (NotTerminated == 1)
- break;
-
- this->Sleep(1000);
- debug("Current working process is %s(%d)",
- GetCurrentProcess()->Name, GetCurrentProcess()->ID);
-
- if (TimeManager->GetCounter() > timeout)
- {
- error("Timeout waiting for processes to terminate");
- break;
- }
-
- TaskingScheduler_OneShot(100);
- }
-
- debug("Tasking stopped");
+ delete (Scheduler::Custom *)__sched_ctx;
}
}