feat: implement new IPC layer

This commit is contained in:
2026-04-01 13:11:03 +02:00
parent 6276f8b162
commit 346977a0f9
34 changed files with 3210 additions and 897 deletions
+142 -76
View File
@@ -18,6 +18,7 @@
#include <Hal/SmpBoot.hpp>
#include <Timekeeping/ApicTimer.hpp>
#include <Api/WinServer.hpp>
#include <Ipc/Ipc.hpp>
// Assembly: context switch with CR3 and FPU state parameters
extern "C" void SchedContextSwitch(uint64_t* oldRsp, uint64_t newRsp, uint64_t newCR3,
@@ -47,6 +48,45 @@ namespace Sched {
return (uint64_t)Memory::VMM::g_paging->PML4;
}
static void SwitchAwayFromBlockedCurrentLocked() {
auto* cpu = Smp::GetCurrentCpuData();
int slot = cpu->currentSlot;
if (slot < 0) {
schedLock.Release();
return;
}
int next = -1;
for (int i = 0; i < MaxProcesses; i++) {
if (processTable[i].state == ProcessState::Ready) {
next = i;
break;
}
}
if (next >= 0) {
cpu->currentSlot = next;
processTable[next].state = ProcessState::Running;
readyCount--;
processTable[next].runningOnCpu = cpu->cpuIndex;
processTable[next].sliceRemaining = TimeSliceMs;
cpu->kernelRsp = processTable[next].kernelStackTop;
cpu->tss->rsp0 = processTable[next].kernelStackTop;
SchedContextSwitch(&processTable[slot].savedRsp, processTable[next].savedRsp,
processTable[next].pml4Phys,
processTable[slot].fpuState, processTable[next].fpuState);
schedLock.Release();
return;
}
cpu->currentSlot = -1;
SchedContextSwitch(&processTable[slot].savedRsp, cpu->idleSavedRsp,
GetKernelCR3(), processTable[slot].fpuState, nullptr);
schedLock.Release();
}
// Startup function for newly spawned processes.
// SchedContextSwitch "returns" here on first schedule.
// The schedLock is held (acquired by the switching-from CPU's Schedule).
@@ -97,6 +137,7 @@ namespace Sched {
processTable[i].killPending = false;
processTable[i].waitingForPid = -1;
processTable[i].sleepUntilTick = 0;
processTable[i].waitingOnObject = nullptr;
processTable[i].redirected = false;
processTable[i].parentPid = -1;
processTable[i].outBuf = nullptr;
@@ -109,6 +150,10 @@ namespace Sched {
processTable[i].keyTail = 0;
processTable[i].termCols = 0;
processTable[i].termRows = 0;
processTable[i].ioOutHandle = -1;
processTable[i].ioInHandle = -1;
processTable[i].ioKeyHandle = -1;
processTable[i].ioWaitsetHandle = -1;
}
nextPid = 0;
@@ -276,6 +321,7 @@ namespace Sched {
proc.killPending = false;
proc.waitingForPid = -1;
proc.sleepUntilTick = 0;
proc.waitingOnObject = nullptr;
// Copy arguments string into process
proc.args[0] = '\0';
@@ -333,12 +379,18 @@ namespace Sched {
proc.keyTail = 0;
proc.termCols = 0;
proc.termRows = 0;
proc.ioOutHandle = -1;
proc.ioInHandle = -1;
proc.ioKeyHandle = -1;
proc.ioWaitsetHandle = -1;
// Initialize FPU state: zero out, then set default FCW and MXCSR
memset(proc.fpuState, 0, 512);
*(uint16_t*)&proc.fpuState[0] = 0x037F; // FCW: default x87 control word
*(uint32_t*)&proc.fpuState[24] = 0x1F80; // MXCSR: default SSE control/status
Ipc::ProcessStartedInSlot(slot, proc.pid);
int resultPid = proc.pid;
schedLock.Release();
@@ -486,6 +538,8 @@ namespace Sched {
processTable[i].sleepUntilTick != 0 &&
now >= processTable[i].sleepUntilTick) {
processTable[i].sleepUntilTick = 0;
processTable[i].waitingForPid = -1;
processTable[i].waitingOnObject = nullptr;
processTable[i].state = ProcessState::Ready;
readyCount++;
}
@@ -554,15 +608,30 @@ namespace Sched {
// Clean up any windows owned by this process
WinServer::CleanupProcess(exitingPid);
// Free I/O redirect buffers
if (proc.outBuf) {
Memory::g_pfa->Free(proc.outBuf);
proc.outBuf = nullptr;
}
if (proc.inBuf) {
Memory::g_pfa->Free(proc.inBuf);
proc.inBuf = nullptr;
}
// Release process-scoped IPC handles/mappings before tearing down the address space.
Ipc::CleanupProcessSlot(slot, exitingPid, proc.pml4Phys);
proc.waitingForPid = -1;
proc.sleepUntilTick = 0;
proc.waitingOnObject = nullptr;
proc.redirected = false;
proc.parentPid = -1;
proc.outBuf = nullptr;
proc.outHead = 0;
proc.outTail = 0;
proc.inBuf = nullptr;
proc.inHead = 0;
proc.inTail = 0;
proc.keyHead = 0;
proc.keyTail = 0;
proc.termCols = 0;
proc.termRows = 0;
proc.ioOutHandle = -1;
proc.ioInHandle = -1;
proc.ioKeyHandle = -1;
proc.ioWaitsetHandle = -1;
Ipc::ProcessExitedInSlot(slot, exitingPid);
// Free all user-space physical pages and page table structures
Memory::VMM::Paging::FreeUserHalf(proc.pml4Phys);
@@ -579,6 +648,8 @@ namespace Sched {
processTable[i].state = ProcessState::Ready;
readyCount++;
processTable[i].waitingForPid = -1;
processTable[i].waitingOnObject = nullptr;
processTable[i].sleepUntilTick = 0;
}
}
@@ -664,6 +735,9 @@ namespace Sched {
readyCount--;
proc.state = ProcessState::Terminated;
proc.killPending = false;
proc.waitingForPid = -1;
proc.sleepUntilTick = 0;
proc.waitingOnObject = nullptr;
// Wake any processes blocked on this PID
for (int i = 0; i < MaxProcesses; i++) {
@@ -672,6 +746,8 @@ namespace Sched {
processTable[i].state = ProcessState::Ready;
readyCount++;
processTable[i].waitingForPid = -1;
processTable[i].waitingOnObject = nullptr;
processTable[i].sleepUntilTick = 0;
}
}
@@ -679,15 +755,26 @@ namespace Sched {
// Safe to clean up resources now -- process is not running anywhere.
WinServer::CleanupProcess(killedPid);
Ipc::CleanupProcessSlot(slot, killedPid, proc.pml4Phys);
if (proc.outBuf) {
Memory::g_pfa->Free(proc.outBuf);
proc.outBuf = nullptr;
}
if (proc.inBuf) {
Memory::g_pfa->Free(proc.inBuf);
proc.inBuf = nullptr;
}
proc.redirected = false;
proc.parentPid = -1;
proc.outBuf = nullptr;
proc.outHead = 0;
proc.outTail = 0;
proc.inBuf = nullptr;
proc.inHead = 0;
proc.inTail = 0;
proc.keyHead = 0;
proc.keyTail = 0;
proc.termCols = 0;
proc.termRows = 0;
proc.ioOutHandle = -1;
proc.ioInHandle = -1;
proc.ioKeyHandle = -1;
proc.ioWaitsetHandle = -1;
Ipc::ProcessExitedInSlot(slot, killedPid);
Memory::VMM::Paging::FreeUserHalf(proc.pml4Phys);
@@ -727,39 +814,10 @@ namespace Sched {
// ExitProcess will wake us when the target terminates.
processTable[slot].state = ProcessState::Blocked;
processTable[slot].waitingForPid = pid;
processTable[slot].waitingOnObject = nullptr;
processTable[slot].sleepUntilTick = 0;
processTable[slot].runningOnCpu = -1;
// Find next ready process to switch to
int next = -1;
for (int i = 0; i < MaxProcesses; i++) {
if (processTable[i].state == ProcessState::Ready) {
next = i;
break;
}
}
if (next >= 0) {
cpu->currentSlot = next;
processTable[next].state = ProcessState::Running;
readyCount--;
processTable[next].runningOnCpu = cpu->cpuIndex;
processTable[next].sliceRemaining = TimeSliceMs;
cpu->kernelRsp = processTable[next].kernelStackTop;
cpu->tss->rsp0 = processTable[next].kernelStackTop;
SchedContextSwitch(&processTable[slot].savedRsp, processTable[next].savedRsp,
processTable[next].pml4Phys,
processTable[slot].fpuState, processTable[next].fpuState);
schedLock.Release();
} else {
// No ready process -- go idle
cpu->currentSlot = -1;
SchedContextSwitch(&processTable[slot].savedRsp, cpu->idleSavedRsp,
GetKernelCR3(), processTable[slot].fpuState, nullptr);
schedLock.Release();
}
SwitchAwayFromBlockedCurrentLocked();
}
void BlockForSleep(uint64_t ms) {
@@ -772,38 +830,46 @@ namespace Sched {
schedLock.Acquire();
processTable[slot].state = ProcessState::Blocked;
processTable[slot].waitingForPid = -1;
processTable[slot].waitingOnObject = nullptr;
processTable[slot].sleepUntilTick = Timekeeping::GetTicks() + ms;
processTable[slot].runningOnCpu = -1;
SwitchAwayFromBlockedCurrentLocked();
}
int next = -1;
void BlockOnObject(void* object, uint64_t timeoutMs) {
if (object == nullptr) return;
auto* cpu = Smp::GetCurrentCpuData();
int slot = cpu->currentSlot;
if (slot < 0) return;
schedLock.Acquire();
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();
}
void WakeObjectWaiters(void* object) {
if (object == nullptr) return;
schedLock.Acquire();
for (int i = 0; i < MaxProcesses; i++) {
if (processTable[i].state == ProcessState::Ready) {
next = i;
break;
}
}
if (next >= 0) {
cpu->currentSlot = next;
processTable[next].state = ProcessState::Running;
readyCount--;
processTable[next].runningOnCpu = cpu->cpuIndex;
processTable[next].sliceRemaining = TimeSliceMs;
cpu->kernelRsp = processTable[next].kernelStackTop;
cpu->tss->rsp0 = processTable[next].kernelStackTop;
SchedContextSwitch(&processTable[slot].savedRsp, processTable[next].savedRsp,
processTable[next].pml4Phys,
processTable[slot].fpuState, processTable[next].fpuState);
schedLock.Release();
} else {
cpu->currentSlot = -1;
SchedContextSwitch(&processTable[slot].savedRsp, cpu->idleSavedRsp,
GetKernelCR3(), processTable[slot].fpuState, nullptr);
schedLock.Release();
if (processTable[i].state != ProcessState::Blocked) continue;
if (processTable[i].waitingOnObject != object) continue;
processTable[i].waitingOnObject = nullptr;
processTable[i].sleepUntilTick = 0;
processTable[i].waitingForPid = -1;
processTable[i].state = ProcessState::Ready;
readyCount++;
}
schedLock.Release();
}
bool IsAlive(int pid) {