mirror of
https://github.com/Fennix-Project/Kernel.git
synced 2025-05-28 15:34:33 +00:00
Refactor task scheduler
This commit is contained in:
parent
66ec562751
commit
df457e8097
150
include/scheduler.hpp
Normal file
150
include/scheduler.hpp
Normal file
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <task.hpp>
|
||||||
|
#include <lock.hpp>
|
||||||
|
|
||||||
|
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<PCB *> &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<PCB *> 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<PCB *> &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
|
||||||
|
{
|
||||||
|
};
|
||||||
|
}
|
115
include/task.hpp
115
include/task.hpp
@ -467,7 +467,7 @@ namespace Tasking
|
|||||||
~PCB();
|
~PCB();
|
||||||
};
|
};
|
||||||
|
|
||||||
class Task : public Interrupts::Handler
|
class Task
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
NewLock(SchedulerLock);
|
NewLock(SchedulerLock);
|
||||||
@ -476,114 +476,43 @@ namespace Tasking
|
|||||||
PID NextPID = 0;
|
PID NextPID = 0;
|
||||||
TID NextTID = 0;
|
TID NextTID = 0;
|
||||||
|
|
||||||
std::list<PCB *> ProcessList;
|
|
||||||
PCB *KernelProcess = nullptr;
|
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);
|
void *Scheduler = nullptr;
|
||||||
bool InvalidTCB(TCB *tcb);
|
void *__sched_ctx = nullptr;
|
||||||
|
|
||||||
/**
|
constexpr TaskArchitecture GetKArch()
|
||||||
* Remove a thread from the scheduler
|
{
|
||||||
*
|
#if defined(a64)
|
||||||
* @note This function is NOT thread safe
|
return x64;
|
||||||
* @note This function does not check if
|
#elif defined(a32)
|
||||||
* the thread is valid nor if it has
|
return x32;
|
||||||
* Terminated status
|
#elif defined(aa64)
|
||||||
*/
|
return ARM64;
|
||||||
bool RemoveThread(TCB *tcb);
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
void PushProcess(PCB *pcb);
|
||||||
* @note This function is NOT thread safe
|
void PopProcess(PCB *pcb);
|
||||||
*/
|
|
||||||
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;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
void *GetScheduler() { return Scheduler; }
|
||||||
PCB *GetKernelProcess() { return KernelProcess; }
|
PCB *GetKernelProcess() { return KernelProcess; }
|
||||||
size_t GetSchedulerTicks() { return SchedulerTicks.load(); }
|
std::list<PCB *> GetProcessList();
|
||||||
size_t GetLastTaskTicks() { return LastTaskTicks.load(); }
|
void Panic();
|
||||||
int GetLastCore() { return LastCore.load(); }
|
bool IsPanic();
|
||||||
std::list<PCB *> GetProcessList() { return ProcessList; }
|
|
||||||
void Panic() { StopScheduler = true; }
|
|
||||||
bool IsPanic() { return StopScheduler; }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Yield the current thread and switch
|
* Yield the current thread and switch
|
||||||
* to another thread if available
|
* to another thread if available
|
||||||
*/
|
*/
|
||||||
__always_inline inline void Yield()
|
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
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the current thread's trap frame
|
* Update the current thread's trap frame
|
||||||
* without switching to another thread
|
* without switching to another thread
|
||||||
*/
|
*/
|
||||||
__always_inline inline void UpdateFrame()
|
void UpdateFrame();
|
||||||
{
|
|
||||||
SchedulerUpdateTrapFrame = true;
|
|
||||||
Yield();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SignalShutdown();
|
void SignalShutdown();
|
||||||
|
|
||||||
@ -670,6 +599,4 @@ namespace Tasking
|
|||||||
#define thisProcess GetCurrentCPU()->CurrentProcess.load()
|
#define thisProcess GetCurrentCPU()->CurrentProcess.load()
|
||||||
#define thisThread GetCurrentCPU()->CurrentThread.load()
|
#define thisThread GetCurrentCPU()->CurrentThread.load()
|
||||||
|
|
||||||
extern "C" void TaskingScheduler_OneShot(int TimeSlice);
|
|
||||||
|
|
||||||
#endif // !__FENNIX_KERNEL_TASKING_H__
|
#endif // !__FENNIX_KERNEL_TASKING_H__
|
||||||
|
@ -228,7 +228,7 @@ namespace Tasking
|
|||||||
|
|
||||||
if (Parent)
|
if (Parent)
|
||||||
Parent->Children.push_back(this);
|
Parent->Children.push_back(this);
|
||||||
ctx->ProcessList.push_back(this);
|
ctx->PushProcess(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
PCB::~PCB()
|
PCB::~PCB()
|
||||||
@ -240,9 +240,7 @@ namespace Tasking
|
|||||||
debug("Removing from process list");
|
debug("Removing from process list");
|
||||||
/* Remove us from the process list so we
|
/* Remove us from the process list so we
|
||||||
don't get scheduled anymore */
|
don't get scheduled anymore */
|
||||||
ctx->ProcessList.erase(std::find(ctx->ProcessList.begin(),
|
ctx->PopProcess(this);
|
||||||
ctx->ProcessList.end(),
|
|
||||||
this));
|
|
||||||
|
|
||||||
debug("Freeing signals");
|
debug("Freeing signals");
|
||||||
delete this->Signals;
|
delete this->Signals;
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <task.hpp>
|
#include <scheduler.hpp>
|
||||||
|
|
||||||
#include <dumper.hpp>
|
#include <dumper.hpp>
|
||||||
#include <convert.h>
|
#include <convert.h>
|
||||||
@ -103,26 +103,187 @@
|
|||||||
#define wut_schedbg(m, ...)
|
#define wut_schedbg(m, ...)
|
||||||
#endif
|
#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)
|
#if defined(a86)
|
||||||
((APIC::Timer *)Interrupts::apicTimer[GetCurrentCPU()->ID])->OneShot(CPU::x86::IRQ16, TimeSlice);
|
asmv("IdleLoop:");
|
||||||
|
asmv("hlt");
|
||||||
|
asmv("jmp IdleLoop");
|
||||||
#elif defined(aa64)
|
#elif defined(aa64)
|
||||||
|
asmv("IdleLoop:");
|
||||||
|
asmv("wfe");
|
||||||
|
asmv("b IdleLoop");
|
||||||
#endif
|
#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<PCB *> &Custom::GetProcessList()
|
||||||
|
{
|
||||||
|
return ProcessList;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Custom::StartScheduler()
|
||||||
|
{
|
||||||
#if defined(a86)
|
#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;
|
CPUData *CurrentCPU = (CPUData *)CPUDataPointer;
|
||||||
fnp_schedbg("%d processes", ProcessList.size());
|
fnp_schedbg("%d processes", ProcessList.size());
|
||||||
@ -133,9 +294,6 @@ namespace Tasking
|
|||||||
#endif
|
#endif
|
||||||
foreach (auto process in ProcessList)
|
foreach (auto process in ProcessList)
|
||||||
{
|
{
|
||||||
if (unlikely(InvalidPCB(process)))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
switch (process->State.load())
|
switch (process->State.load())
|
||||||
{
|
{
|
||||||
case TaskState::Ready:
|
case TaskState::Ready:
|
||||||
@ -157,9 +315,6 @@ namespace Tasking
|
|||||||
|
|
||||||
foreach (auto thread in process->Threads)
|
foreach (auto thread in process->Threads)
|
||||||
{
|
{
|
||||||
if (unlikely(InvalidTCB(thread)))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (thread->State.load() != TaskState::Ready)
|
if (thread->State.load() != TaskState::Ready)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -175,7 +330,7 @@ namespace Tasking
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsa NIF bool Task::GetNextAvailableThread(void *CPUDataPointer)
|
nsa NIF bool Custom::GetNextAvailableThread(void *CPUDataPointer)
|
||||||
{
|
{
|
||||||
CPUData *CurrentCPU = (CPUData *)CPUDataPointer;
|
CPUData *CurrentCPU = (CPUData *)CPUDataPointer;
|
||||||
|
|
||||||
@ -192,16 +347,6 @@ namespace Tasking
|
|||||||
|
|
||||||
TCB *nextThread = CurrentCPU->CurrentProcess->Threads[TempIndex + 1];
|
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)",
|
gnat_schedbg("\"%s\"(%d) and next thread is \"%s\"(%d)",
|
||||||
CurrentCPU->CurrentProcess->Threads[i]->Name,
|
CurrentCPU->CurrentProcess->Threads[i]->Name,
|
||||||
CurrentCPU->CurrentProcess->Threads[i]->ID,
|
CurrentCPU->CurrentProcess->Threads[i]->ID,
|
||||||
@ -234,7 +379,7 @@ namespace Tasking
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsa NIF bool Task::GetNextAvailableProcess(void *CPUDataPointer)
|
nsa NIF bool Custom::GetNextAvailableProcess(void *CPUDataPointer)
|
||||||
{
|
{
|
||||||
CPUData *CurrentCPU = (CPUData *)CPUDataPointer;
|
CPUData *CurrentCPU = (CPUData *)CPUDataPointer;
|
||||||
|
|
||||||
@ -254,12 +399,6 @@ namespace Tasking
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unlikely(InvalidPCB(process)))
|
|
||||||
{
|
|
||||||
gnap_schedbg("Invalid process %#lx", process);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (process->State.load() != TaskState::Ready)
|
if (process->State.load() != TaskState::Ready)
|
||||||
{
|
{
|
||||||
gnap_schedbg("Process %d is not ready", process->ID);
|
gnap_schedbg("Process %d is not ready", process->ID);
|
||||||
@ -268,12 +407,6 @@ namespace Tasking
|
|||||||
|
|
||||||
foreach (auto thread in process->Threads)
|
foreach (auto thread in process->Threads)
|
||||||
{
|
{
|
||||||
if (unlikely(InvalidTCB(thread)))
|
|
||||||
{
|
|
||||||
gnap_schedbg("Invalid thread %#lx", thread);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (thread->State.load() != TaskState::Ready)
|
if (thread->State.load() != TaskState::Ready)
|
||||||
{
|
{
|
||||||
gnap_schedbg("Thread %d is not ready", thread->ID);
|
gnap_schedbg("Thread %d is not ready", thread->ID);
|
||||||
@ -294,18 +427,12 @@ namespace Tasking
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsa NIF bool Task::SchedulerSearchProcessThread(void *CPUDataPointer)
|
nsa NIF bool Custom::SchedulerSearchProcessThread(void *CPUDataPointer)
|
||||||
{
|
{
|
||||||
CPUData *CurrentCPU = (CPUData *)CPUDataPointer;
|
CPUData *CurrentCPU = (CPUData *)CPUDataPointer;
|
||||||
|
|
||||||
foreach (auto process in ProcessList)
|
foreach (auto process in ProcessList)
|
||||||
{
|
{
|
||||||
if (unlikely(InvalidPCB(process)))
|
|
||||||
{
|
|
||||||
sspt_schedbg("Invalid process %#lx", process);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (process->State.load() != TaskState::Ready)
|
if (process->State.load() != TaskState::Ready)
|
||||||
{
|
{
|
||||||
sspt_schedbg("Process %d is not ready", process->ID);
|
sspt_schedbg("Process %d is not ready", process->ID);
|
||||||
@ -314,12 +441,6 @@ namespace Tasking
|
|||||||
|
|
||||||
foreach (auto thread in process->Threads)
|
foreach (auto thread in process->Threads)
|
||||||
{
|
{
|
||||||
if (unlikely(InvalidTCB(thread)))
|
|
||||||
{
|
|
||||||
sspt_schedbg("Invalid thread %#lx", thread);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (thread->State.load() != TaskState::Ready)
|
if (thread->State.load() != TaskState::Ready)
|
||||||
{
|
{
|
||||||
sspt_schedbg("Thread %d is not ready", thread->ID);
|
sspt_schedbg("Thread %d is not ready", thread->ID);
|
||||||
@ -339,13 +460,10 @@ namespace Tasking
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsa NIF void Task::UpdateProcessState()
|
nsa NIF void Custom::UpdateProcessState()
|
||||||
{
|
{
|
||||||
foreach (auto process in ProcessList)
|
foreach (auto process in ProcessList)
|
||||||
{
|
{
|
||||||
if (unlikely(InvalidPCB(process)))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (process->State.load() == TaskState::Terminated)
|
if (process->State.load() == TaskState::Terminated)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -375,13 +493,10 @@ namespace Tasking
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nsa NIF void Task::WakeUpThreads()
|
nsa NIF void Custom::WakeUpThreads()
|
||||||
{
|
{
|
||||||
foreach (auto process in ProcessList)
|
foreach (auto process in ProcessList)
|
||||||
{
|
{
|
||||||
if (unlikely(InvalidPCB(process)))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Tasking::TaskState pState = process->State.load();
|
Tasking::TaskState pState = process->State.load();
|
||||||
if (pState != TaskState::Ready &&
|
if (pState != TaskState::Ready &&
|
||||||
pState != TaskState::Sleeping &&
|
pState != TaskState::Sleeping &&
|
||||||
@ -390,9 +505,6 @@ namespace Tasking
|
|||||||
|
|
||||||
foreach (auto thread in process->Threads)
|
foreach (auto thread in process->Threads)
|
||||||
{
|
{
|
||||||
if (unlikely(InvalidTCB(thread)))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (likely(thread->State.load() != TaskState::Sleeping))
|
if (likely(thread->State.load() != TaskState::Sleeping))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -415,7 +527,7 @@ namespace Tasking
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nsa NIF void Task::CleanupTerminated()
|
nsa NIF void Custom::CleanupTerminated()
|
||||||
{
|
{
|
||||||
foreach (auto pcb in ProcessList)
|
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))
|
if (unlikely(StopScheduler))
|
||||||
{
|
{
|
||||||
@ -450,8 +562,8 @@ namespace Tasking
|
|||||||
this->LastCore.store(CurrentCPU->ID);
|
this->LastCore.store(CurrentCPU->ID);
|
||||||
schedbg("Scheduler called on CPU %d.", CurrentCPU->ID);
|
schedbg("Scheduler called on CPU %d.", CurrentCPU->ID);
|
||||||
|
|
||||||
if (unlikely(InvalidPCB(CurrentCPU->CurrentProcess.load()) ||
|
if (unlikely(!CurrentCPU->CurrentProcess.load() ||
|
||||||
InvalidTCB(CurrentCPU->CurrentThread.load())))
|
!CurrentCPU->CurrentThread.load()))
|
||||||
{
|
{
|
||||||
schedbg("Invalid process or thread. Finding a new one.");
|
schedbg("Invalid process or thread. Finding a new one.");
|
||||||
ProcessNotChanged = true;
|
ProcessNotChanged = true;
|
||||||
@ -524,9 +636,7 @@ namespace Tasking
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
warn("Unwanted reach!");
|
assert(!"Unwanted code execution");
|
||||||
TaskingScheduler_OneShot(100);
|
|
||||||
goto End;
|
|
||||||
|
|
||||||
Idle:
|
Idle:
|
||||||
ProcessNotChanged = true;
|
ProcessNotChanged = true;
|
||||||
@ -586,7 +696,7 @@ namespace Tasking
|
|||||||
if (!ProcessNotChanged)
|
if (!ProcessNotChanged)
|
||||||
(&CurrentCPU->CurrentProcess->Info)->LastUpdateTime = TimeManager->GetCounter();
|
(&CurrentCPU->CurrentProcess->Info)->LastUpdateTime = TimeManager->GetCounter();
|
||||||
(&CurrentCPU->CurrentThread->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 &&
|
if (CurrentCPU->CurrentThread->Security.IsDebugEnabled &&
|
||||||
CurrentCPU->CurrentThread->Security.IsKernelDebugEnabled)
|
CurrentCPU->CurrentThread->Security.IsKernelDebugEnabled)
|
||||||
@ -627,42 +737,74 @@ namespace Tasking
|
|||||||
Frame->rip, Frame->rflags, Frame->InterruptNumber, Frame->ErrorCode);
|
Frame->rip, Frame->rflags, Frame->InterruptNumber, Frame->ErrorCode);
|
||||||
schedbg("================================================================");
|
schedbg("================================================================");
|
||||||
|
|
||||||
End:
|
|
||||||
this->SchedulerTicks.store(size_t(TimeManager->GetCounter() - SchedTmpTicks));
|
this->SchedulerTicks.store(size_t(TimeManager->GetCounter() - SchedTmpTicks));
|
||||||
CurrentCPU->CurrentProcess->PageTable->Update();
|
CurrentCPU->CurrentProcess->PageTable->Update();
|
||||||
}
|
}
|
||||||
|
|
||||||
nsa NIF void Task::OnInterruptReceived(CPU::TrapFrame *Frame)
|
nsa NIF void Custom::OnInterruptReceived(CPU::TrapFrame *Frame)
|
||||||
{
|
{
|
||||||
SmartCriticalSection(SchedulerLock);
|
SmartCriticalSection(SchedulerLock);
|
||||||
this->Schedule(Frame);
|
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");
|
#if defined(a86)
|
||||||
}
|
// Map the IRQ16 to the first CPU.
|
||||||
|
((APIC::APIC *)Interrupts::apic[0])->RedirectIRQ(0, CPU::x86::IRQ16 - CPU::x86::IRQ0, 1);
|
||||||
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); }
|
|
||||||
#endif
|
#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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
332
tasking/task.cpp
332
tasking/task.cpp
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
#include <task.hpp>
|
#include <task.hpp>
|
||||||
|
|
||||||
|
#include <scheduler.hpp>
|
||||||
#include <dumper.hpp>
|
#include <dumper.hpp>
|
||||||
#include <convert.h>
|
#include <convert.h>
|
||||||
#include <lock.hpp>
|
#include <lock.hpp>
|
||||||
@ -46,104 +47,6 @@
|
|||||||
|
|
||||||
namespace Tasking
|
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()
|
PCB *Task::GetCurrentProcess()
|
||||||
{
|
{
|
||||||
return GetCurrentCPU()->CurrentProcess.load();
|
return GetCurrentCPU()->CurrentProcess.load();
|
||||||
@ -156,34 +59,52 @@ namespace Tasking
|
|||||||
|
|
||||||
PCB *Task::GetProcessByID(TID ID)
|
PCB *Task::GetProcessByID(TID ID)
|
||||||
{
|
{
|
||||||
SmartLock(TaskingLock);
|
return ((Scheduler::Base *)Scheduler)->GetProcessByID(ID);
|
||||||
foreach (auto p in ProcessList)
|
|
||||||
{
|
|
||||||
if (p->ID == ID)
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TCB *Task::GetThreadByID(TID ID)
|
TCB *Task::GetThreadByID(TID ID)
|
||||||
{
|
{
|
||||||
SmartLock(TaskingLock);
|
return ((Scheduler::Base *)Scheduler)->GetThreadByID(ID);
|
||||||
foreach (auto p in ProcessList)
|
}
|
||||||
{
|
|
||||||
foreach (auto t in p->Threads)
|
std::list<PCB *> Task::GetProcessList()
|
||||||
{
|
{
|
||||||
if (t->ID == ID)
|
return ((Scheduler::Base *)Scheduler)->GetProcessList();
|
||||||
return t;
|
}
|
||||||
}
|
|
||||||
}
|
void Task::Panic()
|
||||||
return nullptr;
|
{
|
||||||
|
((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)
|
void Task::WaitForProcess(PCB *pcb)
|
||||||
{
|
{
|
||||||
if (unlikely(InvalidPCB(pcb)))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (pcb->State == TaskState::UnknownStatus)
|
if (pcb->State == TaskState::UnknownStatus)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -198,9 +119,6 @@ namespace Tasking
|
|||||||
|
|
||||||
void Task::WaitForThread(TCB *tcb)
|
void Task::WaitForThread(TCB *tcb)
|
||||||
{
|
{
|
||||||
if (unlikely(InvalidTCB(tcb)))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (tcb->State == TaskState::UnknownStatus)
|
if (tcb->State == TaskState::UnknownStatus)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -215,9 +133,6 @@ namespace Tasking
|
|||||||
|
|
||||||
void Task::WaitForProcessStatus(PCB *pcb, TaskState status)
|
void Task::WaitForProcessStatus(PCB *pcb, TaskState status)
|
||||||
{
|
{
|
||||||
if (unlikely(InvalidPCB(pcb)))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (pcb->State == TaskState::UnknownStatus)
|
if (pcb->State == TaskState::UnknownStatus)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -230,9 +145,6 @@ namespace Tasking
|
|||||||
|
|
||||||
void Task::WaitForThreadStatus(TCB *tcb, TaskState status)
|
void Task::WaitForThreadStatus(TCB *tcb, TaskState status)
|
||||||
{
|
{
|
||||||
if (unlikely(InvalidTCB(tcb)))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (tcb->State == TaskState::UnknownStatus)
|
if (tcb->State == TaskState::UnknownStatus)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -277,7 +189,7 @@ namespace Tasking
|
|||||||
GetCurrentProcess()->Name, GetCurrentProcess()->ID,
|
GetCurrentProcess()->Name, GetCurrentProcess()->ID,
|
||||||
GetCurrentThread()->Name, GetCurrentThread()->ID);
|
GetCurrentThread()->Name, GetCurrentThread()->ID);
|
||||||
|
|
||||||
foreach (auto pcb in ProcessList)
|
foreach (auto pcb in((Scheduler::Base *)Scheduler)->GetProcessList())
|
||||||
{
|
{
|
||||||
if (pcb->State == TaskState::Terminated ||
|
if (pcb->State == TaskState::Terminated ||
|
||||||
pcb->State == TaskState::Zombie)
|
pcb->State == TaskState::Zombie)
|
||||||
@ -295,13 +207,10 @@ namespace Tasking
|
|||||||
}
|
}
|
||||||
|
|
||||||
__no_sanitize("undefined")
|
__no_sanitize("undefined")
|
||||||
TCB *Task::CreateThread(PCB *Parent,
|
TCB *Task::CreateThread(PCB *Parent, IP EntryPoint,
|
||||||
IP EntryPoint,
|
const char **argv, const char **envp,
|
||||||
const char **argv,
|
|
||||||
const char **envp,
|
|
||||||
const std::vector<AuxiliaryVector> &auxv,
|
const std::vector<AuxiliaryVector> &auxv,
|
||||||
TaskArchitecture arch,
|
TaskArchitecture arch, TaskCompatibility Compatibility,
|
||||||
TaskCompatibility Compatibility,
|
|
||||||
bool ThreadNotReady)
|
bool ThreadNotReady)
|
||||||
{
|
{
|
||||||
SmartLock(TaskingLock);
|
SmartLock(TaskingLock);
|
||||||
@ -310,10 +219,8 @@ namespace Tasking
|
|||||||
Compatibility, ThreadNotReady);
|
Compatibility, ThreadNotReady);
|
||||||
}
|
}
|
||||||
|
|
||||||
PCB *Task::CreateProcess(PCB *Parent,
|
PCB *Task::CreateProcess(PCB *Parent, const char *Name,
|
||||||
const char *Name,
|
TaskExecutionMode ExecutionMode, bool UseKernelPageTable,
|
||||||
TaskExecutionMode ExecutionMode,
|
|
||||||
bool UseKernelPageTable,
|
|
||||||
uint16_t UserID, uint16_t GroupID)
|
uint16_t UserID, uint16_t GroupID)
|
||||||
{
|
{
|
||||||
SmartLock(TaskingLock);
|
SmartLock(TaskingLock);
|
||||||
@ -323,169 +230,40 @@ namespace Tasking
|
|||||||
|
|
||||||
void Task::StartScheduler()
|
void Task::StartScheduler()
|
||||||
{
|
{
|
||||||
#if defined(a86)
|
((Scheduler::Base *)Scheduler)->StartScheduler();
|
||||||
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
|
|
||||||
debug("Tasking Started");
|
debug("Tasking Started");
|
||||||
}
|
}
|
||||||
|
|
||||||
Task::Task(const IP EntryPoint) : Interrupts::Handler(16) /* IRQ16 */
|
Task::Task(const IP EntryPoint)
|
||||||
{
|
{
|
||||||
#if defined(a64)
|
/* I don't know if this is the best way to do this. */
|
||||||
// Map the IRQ16 to the first CPU.
|
Scheduler::Custom *custom_sched = new Scheduler::Custom(this);
|
||||||
((APIC::APIC *)Interrupts::apic[0])->RedirectIRQ(0, CPU::x86::IRQ16 - CPU::x86::IRQ0, 1);
|
Scheduler::Base *sched = r_cst(Scheduler::Base *, custom_sched);
|
||||||
#elif defined(a32)
|
__sched_ctx = custom_sched;
|
||||||
#elif defined(aa64)
|
Scheduler = sched;
|
||||||
#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
|
|
||||||
|
|
||||||
KernelProcess = CreateProcess(nullptr, "Kernel",
|
KernelProcess = CreateProcess(nullptr, "Kernel",
|
||||||
TaskExecutionMode::Kernel, true);
|
TaskExecutionMode::Kernel, true);
|
||||||
KernelProcess->PageTable = KernelPageTable;
|
KernelProcess->PageTable = KernelPageTable;
|
||||||
TCB *kthrd = CreateThread(KernelProcess, EntryPoint,
|
TCB *kthrd = CreateThread(KernelProcess, EntryPoint,
|
||||||
nullptr, nullptr,
|
nullptr, nullptr,
|
||||||
std::vector<AuxiliaryVector>(), Arch);
|
std::vector<AuxiliaryVector>(), GetKArch());
|
||||||
kthrd->Rename("Main Thread");
|
kthrd->Rename("Main Thread");
|
||||||
debug("Created Kernel Process: %s and Thread: %s",
|
debug("Created Kernel Process: %s and Thread: %s",
|
||||||
KernelProcess->Name, kthrd->Name);
|
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))
|
if (!CPU::Interrupts(CPU::Check))
|
||||||
{
|
{
|
||||||
error("Interrupts are not enabled.");
|
error("Interrupts are not enabled.");
|
||||||
CPU::Interrupts(CPU::Enable);
|
CPU::Interrupts(CPU::Enable);
|
||||||
}
|
}
|
||||||
|
|
||||||
IdleProcess = CreateProcess(nullptr, (char *)"Idle",
|
((Scheduler::Base *)Scheduler)->StartIdleProcess();
|
||||||
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;
|
|
||||||
}
|
|
||||||
debug("Tasking is ready");
|
debug("Tasking is ready");
|
||||||
}
|
}
|
||||||
|
|
||||||
Task::~Task()
|
Task::~Task()
|
||||||
{
|
{
|
||||||
debug("Destructor called");
|
delete (Scheduler::Custom *)__sched_ctx;
|
||||||
{
|
|
||||||
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");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user