feat: further kernel power and power optimizations
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
#include <CppLib/Stream.hpp>
|
||||
#include <CppLib/Spinlock.hpp>
|
||||
#include <Hal/Apic/Apic.hpp>
|
||||
#include <Hal/Apic/Interrupts.hpp>
|
||||
#include <Hal/GDT.hpp>
|
||||
#include <Hal/SmpBoot.hpp>
|
||||
#include <Timekeeping/ApicTimer.hpp>
|
||||
@@ -50,6 +51,41 @@ namespace Sched {
|
||||
return (uint64_t)Memory::VMM::g_paging->PML4;
|
||||
}
|
||||
|
||||
static void RescheduleIpiHandler(uint8_t) {
|
||||
auto* cpu = Smp::GetCurrentCpuData();
|
||||
if (cpu == nullptr || cpu->currentSlot >= 0 || readyCount <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
Schedule();
|
||||
}
|
||||
|
||||
static void KickOneIdleCpu(int sourceCpuIndex) {
|
||||
if (readyCount <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto tryKick = [&](Smp::CpuData* target) {
|
||||
if (target == nullptr || !target->started) return false;
|
||||
if (target->cpuIndex == sourceCpuIndex) return false;
|
||||
if (target->currentSlot >= 0) return false;
|
||||
|
||||
Hal::LocalApic::SendFixedIpi(target->lapicId,
|
||||
Hal::IRQ_VECTOR_BASE + Hal::IRQ_RESCHEDULE);
|
||||
return true;
|
||||
};
|
||||
|
||||
if (tryKick(Smp::GetCpuData(0))) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < Smp::GetCpuCount(); i++) {
|
||||
if (tryKick(Smp::GetCpuData(i))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void SwitchAwayFromBlockedCurrentLocked() {
|
||||
auto* cpu = Smp::GetCurrentCpuData();
|
||||
int slot = cpu->currentSlot;
|
||||
@@ -160,6 +196,7 @@ namespace Sched {
|
||||
}
|
||||
|
||||
nextPid = 0;
|
||||
Hal::RegisterIrqHandler(Hal::IRQ_RESCHEDULE, RescheduleIpiHandler);
|
||||
|
||||
Kt::KernelLogStream(Kt::OK, "Sched") << "Initialized (" << MaxProcesses
|
||||
<< " process slots, " << (uint64_t)TimeSliceMs << " ms time slice)";
|
||||
@@ -398,6 +435,7 @@ namespace Sched {
|
||||
|
||||
int resultPid = proc.pid;
|
||||
schedLock.Release();
|
||||
KickOneIdleCpu(Smp::GetCurrentCpuData() ? Smp::GetCurrentCpuData()->cpuIndex : -1);
|
||||
|
||||
return resultPid;
|
||||
}
|
||||
@@ -448,6 +486,8 @@ namespace Sched {
|
||||
}
|
||||
|
||||
void RunBspMaintenance() {
|
||||
bool wokeProcesses = false;
|
||||
|
||||
schedLock.Acquire();
|
||||
uint64_t now = Timekeeping::GetTicks();
|
||||
for (int i = 0; i < MaxProcesses; i++) {
|
||||
@@ -459,10 +499,15 @@ namespace Sched {
|
||||
processTable[i].waitingOnObject = nullptr;
|
||||
processTable[i].state = ProcessState::Ready;
|
||||
readyCount++;
|
||||
wokeProcesses = true;
|
||||
}
|
||||
}
|
||||
schedLock.Release();
|
||||
|
||||
if (wokeProcesses) {
|
||||
KickOneIdleCpu(0);
|
||||
}
|
||||
|
||||
ReclaimTerminated();
|
||||
}
|
||||
|
||||
@@ -704,6 +749,10 @@ namespace Sched {
|
||||
processTable[next].runningOnCpu = cpu->cpuIndex;
|
||||
processTable[next].sliceRemaining = TimeSliceMs;
|
||||
|
||||
if (readyCount > 0) {
|
||||
KickOneIdleCpu(cpu->cpuIndex);
|
||||
}
|
||||
|
||||
uint64_t newCR3 = processTable[next].pml4Phys;
|
||||
cpu->kernelRsp = processTable[next].kernelStackTop;
|
||||
cpu->tss->rsp0 = processTable[next].kernelStackTop;
|
||||
@@ -789,6 +838,7 @@ namespace Sched {
|
||||
}
|
||||
|
||||
schedLock.Release();
|
||||
KickOneIdleCpu(Smp::GetCurrentCpuData() ? Smp::GetCurrentCpuData()->cpuIndex : -1);
|
||||
|
||||
// Safe to clean up resources now -- process is not running anywhere.
|
||||
WinServer::CleanupProcess(killedPid);
|
||||
@@ -898,9 +948,38 @@ namespace Sched {
|
||||
SwitchAwayFromBlockedCurrentLocked();
|
||||
}
|
||||
|
||||
bool BlockOnObjectIf(void* object, uint64_t timeoutMs,
|
||||
bool (*shouldBlock)(void*), void* context) {
|
||||
if (object == nullptr || shouldBlock == nullptr) return false;
|
||||
|
||||
auto* cpu = Smp::GetCurrentCpuData();
|
||||
if (cpu == nullptr) return false;
|
||||
|
||||
int slot = cpu->currentSlot;
|
||||
if (slot < 0) return false;
|
||||
|
||||
schedLock.Acquire();
|
||||
|
||||
if (!shouldBlock(context)) {
|
||||
schedLock.Release();
|
||||
return false;
|
||||
}
|
||||
|
||||
processTable[slot].state = ProcessState::Blocked;
|
||||
processTable[slot].waitingForPid = -1;
|
||||
processTable[slot].waitingOnObject = object;
|
||||
processTable[slot].sleepUntilTick = (timeoutMs > 0)
|
||||
? (Timekeeping::GetTicks() + timeoutMs)
|
||||
: 0;
|
||||
processTable[slot].runningOnCpu = -1;
|
||||
SwitchAwayFromBlockedCurrentLocked();
|
||||
return true;
|
||||
}
|
||||
|
||||
void WakeObjectWaiters(void* object) {
|
||||
if (object == nullptr) return;
|
||||
|
||||
bool wokeAny = false;
|
||||
schedLock.Acquire();
|
||||
for (int i = 0; i < MaxProcesses; i++) {
|
||||
if (processTable[i].state != ProcessState::Blocked) continue;
|
||||
@@ -911,8 +990,13 @@ namespace Sched {
|
||||
processTable[i].waitingForPid = -1;
|
||||
processTable[i].state = ProcessState::Ready;
|
||||
readyCount++;
|
||||
wokeAny = true;
|
||||
}
|
||||
schedLock.Release();
|
||||
|
||||
if (wokeAny) {
|
||||
KickOneIdleCpu(Smp::GetCurrentCpuData() ? Smp::GetCurrentCpuData()->cpuIndex : -1);
|
||||
}
|
||||
}
|
||||
|
||||
bool IsAlive(int pid) {
|
||||
|
||||
Reference in New Issue
Block a user