feat: add threading to Scheduler, fix desktop background selection freeze issue
This commit is contained in:
+402
-80
@@ -28,8 +28,11 @@
|
||||
extern "C" void SchedContextSwitch(uint64_t* oldRsp, uint64_t newRsp, uint64_t newCR3,
|
||||
uint8_t* oldFpuArea, uint8_t* newFpuArea);
|
||||
|
||||
// Assembly: jump to user mode via IRETQ
|
||||
extern "C" void JumpToUserMode(uint64_t rip, uint64_t rsp);
|
||||
// Assembly: jump to user mode via IRETQ.
|
||||
// `arg` is delivered as the user-mode RDI (SystemV first argument).
|
||||
// For freshly spawned processes this is 0; for SpawnThread it is the
|
||||
// user-supplied entry argument.
|
||||
extern "C" void JumpToUserMode(uint64_t rip, uint64_t rsp, uint64_t arg);
|
||||
|
||||
namespace Sched {
|
||||
|
||||
@@ -145,8 +148,10 @@ namespace Sched {
|
||||
// Set up per-CPU TSS RSP0 for hardware interrupts from ring 3
|
||||
cpu->tss->rsp0 = proc.kernelStackTop;
|
||||
|
||||
// Jump to user mode (never returns)
|
||||
JumpToUserMode(proc.entryPoint, proc.userStackTop);
|
||||
// Jump to user mode (never returns).
|
||||
// For main threads threadArg is 0 (libc _start ignores RDI);
|
||||
// for sibling threads it carries the user-supplied argument.
|
||||
JumpToUserMode(proc.entryPoint, proc.userStackTop, proc.threadArg);
|
||||
}
|
||||
|
||||
ExitProcess();
|
||||
@@ -196,6 +201,10 @@ namespace Sched {
|
||||
processTable[i].ioInHandle = -1;
|
||||
processTable[i].ioKeyHandle = -1;
|
||||
processTable[i].ioWaitsetHandle = -1;
|
||||
processTable[i].primarySlot = -1;
|
||||
processTable[i].joinerSlot = -1;
|
||||
processTable[i].exitCode = 0;
|
||||
processTable[i].joinable = true;
|
||||
}
|
||||
|
||||
nextPid = 0;
|
||||
@@ -347,6 +356,10 @@ namespace Sched {
|
||||
for (; i < 63 && vfsPath[i]; i++) proc.name[i] = vfsPath[i];
|
||||
proc.name[i] = '\0';
|
||||
}
|
||||
proc.primarySlot = slot; // main thread owns per-process state
|
||||
proc.joinerSlot = -1;
|
||||
proc.exitCode = 0;
|
||||
proc.joinable = false; // main thread is reaped by BSP, not joined
|
||||
proc.savedRsp = (uint64_t)sp;
|
||||
proc.stackBase = (uint64_t)kernelStackBase;
|
||||
proc.entryPoint = entry;
|
||||
@@ -440,6 +453,266 @@ namespace Sched {
|
||||
return resultPid;
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
// Threading
|
||||
//
|
||||
// Every thread is a slot in processTable. The main thread's primarySlot
|
||||
// points to itself and owns process-level state (PML4, IPC handles,
|
||||
// cwd/user/args, redirected I/O). A sibling thread copies pml4Phys from
|
||||
// the primary so context-switch is cheap, but per-process getters use
|
||||
// primarySlot to reach the canonical state.
|
||||
//
|
||||
// Sibling-thread lifecycle:
|
||||
// * SpawnThread: allocate slot + kernel stack; user provides user stack.
|
||||
// * ExitCurrentThread: slot -> Terminated, kernel stack kept alive for
|
||||
// the joiner; joiner reads exitCode and frees the kernel stack.
|
||||
// * ExitProcess from the main thread sweeps any still-Terminated
|
||||
// sibling slots (no joiner ever arrived) and tears the rest down.
|
||||
// ====================================================================
|
||||
int SpawnThread(uint64_t entry, uint64_t arg, uint64_t userStackTop) {
|
||||
auto* cpu = Smp::GetCurrentCpuData();
|
||||
if (cpu == nullptr || cpu->currentSlot < 0) return -1;
|
||||
if (entry == 0 || userStackTop < 16) return -1;
|
||||
|
||||
int callerSlot = cpu->currentSlot;
|
||||
int primarySlot_ = processTable[callerSlot].primarySlot;
|
||||
if (primarySlot_ < 0) primarySlot_ = callerSlot;
|
||||
uint64_t sharedPml4 = processTable[primarySlot_].pml4Phys;
|
||||
int processPid = processTable[primarySlot_].pid;
|
||||
if (sharedPml4 == 0) return -1;
|
||||
|
||||
// We do not write to the user stack from kernel mode (that would
|
||||
// require validating the user VA against the process page tables).
|
||||
// Userspace is responsible for ensuring the thread entry calls
|
||||
// SYS_THREAD_EXIT; the libc trampoline does this. The kernel only
|
||||
// enforces SystemV alignment by handing the entry RSP = 16n - 8.
|
||||
uint64_t userRsp = (userStackTop & ~0xFULL) - 8;
|
||||
|
||||
// Allocate kernel stack.
|
||||
void* stackMem = Memory::g_pfa->ReallocConsecutive(nullptr, StackPages);
|
||||
if (stackMem == nullptr) return -1;
|
||||
memset(stackMem, 0, StackSize);
|
||||
uint8_t* kernelStackBase = (uint8_t*)stackMem;
|
||||
uint64_t kernelStackTop = (uint64_t)kernelStackBase + StackSize;
|
||||
|
||||
// Initial kernel frame -- SchedContextSwitch "returns" into ProcessStartup.
|
||||
uint64_t* sp = (uint64_t*)kernelStackTop;
|
||||
*(--sp) = (uint64_t)ProcessStartup;
|
||||
*(--sp) = 0; *(--sp) = 0; *(--sp) = 0;
|
||||
*(--sp) = 0; *(--sp) = 0; *(--sp) = 0;
|
||||
|
||||
schedLock.Acquire();
|
||||
|
||||
int slot = -1;
|
||||
for (int i = 0; i < MaxProcesses; i++) {
|
||||
if (processTable[i].state == ProcessState::Free) { slot = i; break; }
|
||||
}
|
||||
if (slot < 0) {
|
||||
schedLock.Release();
|
||||
Memory::g_pfa->Free(stackMem, StackPages);
|
||||
return -1;
|
||||
}
|
||||
|
||||
Process& thr = processTable[slot];
|
||||
thr.pid = nextPid++;
|
||||
thr.state = ProcessState::Ready;
|
||||
readyCount++;
|
||||
thr.runningOnCpu = -1;
|
||||
thr.killPending = false;
|
||||
thr.reapReady = false;
|
||||
thr.startPending = false;
|
||||
thr.waitingForPid = -1;
|
||||
thr.sleepUntilTick = 0;
|
||||
thr.waitingOnObject = nullptr;
|
||||
thr.primarySlot = primarySlot_;
|
||||
thr.joinerSlot = -1;
|
||||
thr.exitCode = 0;
|
||||
thr.joinable = true;
|
||||
thr.threadArg = arg;
|
||||
thr.savedRsp = (uint64_t)sp;
|
||||
thr.stackBase = (uint64_t)kernelStackBase;
|
||||
thr.entryPoint = entry;
|
||||
thr.userStackTop = userRsp;
|
||||
thr.kernelStackTop = kernelStackTop;
|
||||
thr.pml4Phys = sharedPml4; // shared with primary, NOT owned
|
||||
thr.sliceRemaining = TimeSliceMs;
|
||||
thr.cpuTimeMs = 0;
|
||||
thr.heapNext = 0;
|
||||
thr.readdirCursor = 0;
|
||||
thr.parentPid = processPid;
|
||||
thr.redirected = false;
|
||||
thr.outBuf = nullptr; thr.outHead = 0; thr.outTail = 0;
|
||||
thr.inBuf = nullptr; thr.inHead = 0; thr.inTail = 0;
|
||||
thr.keyHead = 0; thr.keyTail = 0;
|
||||
thr.termCols = 0; thr.termRows = 0;
|
||||
thr.ioOutHandle = -1; thr.ioInHandle = -1;
|
||||
thr.ioKeyHandle = -1; thr.ioWaitsetHandle = -1;
|
||||
thr.args[0] = '\0'; thr.user[0] = '\0'; thr.cwd[0] = '\0';
|
||||
|
||||
// Derive a debug name from the primary's name.
|
||||
{
|
||||
const char* base = processTable[primarySlot_].name;
|
||||
int i = 0;
|
||||
for (; i < 58 && base[i]; i++) thr.name[i] = base[i];
|
||||
thr.name[i++] = ':';
|
||||
thr.name[i++] = 't';
|
||||
thr.name[i] = '\0';
|
||||
}
|
||||
|
||||
memset(thr.fpuState, 0, 512);
|
||||
*(uint16_t*)&thr.fpuState[0] = 0x037F;
|
||||
*(uint32_t*)&thr.fpuState[24] = 0x1F80;
|
||||
|
||||
int tid = thr.pid;
|
||||
schedLock.Release();
|
||||
|
||||
KickOneIdleCpu(cpu->cpuIndex);
|
||||
return tid;
|
||||
}
|
||||
|
||||
// Switch away from a slot we have just marked non-runnable while holding
|
||||
// schedLock. Mirrors SwitchAwayFromBlockedCurrentLocked but does NOT
|
||||
// assume the caller will be resumed -- used by ExitCurrentThread.
|
||||
static void SwitchAwayFromExitingThreadLocked(int slot, Process& thr) {
|
||||
auto* cpu = Smp::GetCurrentCpuData();
|
||||
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;
|
||||
if (readyCount > 0) {
|
||||
KickOneIdleCpu(cpu->cpuIndex);
|
||||
}
|
||||
SchedContextSwitch(&thr.savedRsp, processTable[next].savedRsp,
|
||||
processTable[next].pml4Phys,
|
||||
thr.fpuState, processTable[next].fpuState);
|
||||
} else {
|
||||
cpu->currentSlot = -1;
|
||||
SchedContextSwitch(&thr.savedRsp, cpu->idleSavedRsp,
|
||||
GetKernelCR3(),
|
||||
thr.fpuState, nullptr);
|
||||
}
|
||||
schedLock.Release();
|
||||
(void)slot;
|
||||
}
|
||||
|
||||
[[noreturn]] void ExitCurrentThread(int exitCode) {
|
||||
auto* cpu = Smp::GetCurrentCpuData();
|
||||
int slot = cpu->currentSlot;
|
||||
if (slot < 0) {
|
||||
for (;;) asm volatile("hlt");
|
||||
}
|
||||
|
||||
Process& thr = processTable[slot];
|
||||
int primarySlot_ = thr.primarySlot;
|
||||
if (primarySlot_ < 0 || primarySlot_ == slot) {
|
||||
// This is the main thread (or an orphan): full process exit.
|
||||
thr.exitCode = exitCode;
|
||||
ExitProcess();
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
thr.killPending = false;
|
||||
thr.startPending = false;
|
||||
thr.exitCode = exitCode;
|
||||
|
||||
schedLock.Acquire();
|
||||
thr.state = ProcessState::Terminated;
|
||||
thr.runningOnCpu = -1;
|
||||
thr.waitingForPid = -1;
|
||||
thr.sleepUntilTick = 0;
|
||||
thr.waitingOnObject = nullptr;
|
||||
|
||||
// Wake any joiner blocked on this slot.
|
||||
void* joinObj = &processTable[slot];
|
||||
for (int i = 0; i < MaxProcesses; i++) {
|
||||
if (processTable[i].state == ProcessState::Blocked &&
|
||||
processTable[i].waitingOnObject == joinObj) {
|
||||
processTable[i].state = ProcessState::Ready;
|
||||
readyCount++;
|
||||
processTable[i].waitingOnObject = nullptr;
|
||||
processTable[i].sleepUntilTick = 0;
|
||||
processTable[i].waitingForPid = -1;
|
||||
}
|
||||
}
|
||||
|
||||
SwitchAwayFromExitingThreadLocked(slot, thr);
|
||||
// Unreachable: the slot is Terminated, nobody resumes us.
|
||||
for (;;) asm volatile("hlt");
|
||||
}
|
||||
|
||||
int JoinThread(int tid, int* outExitCode) {
|
||||
auto* cpu = Smp::GetCurrentCpuData();
|
||||
if (cpu == nullptr || cpu->currentSlot < 0) return -1;
|
||||
int callerSlot = cpu->currentSlot;
|
||||
int callerPrimary = processTable[callerSlot].primarySlot;
|
||||
if (callerPrimary < 0) callerPrimary = callerSlot;
|
||||
if (tid <= 0) return -1;
|
||||
|
||||
// Locate the sibling slot under lock.
|
||||
schedLock.Acquire();
|
||||
int target = -1;
|
||||
for (int i = 0; i < MaxProcesses; i++) {
|
||||
if (i == callerSlot) continue;
|
||||
if (processTable[i].pid != tid) continue;
|
||||
if (processTable[i].primarySlot != callerPrimary) continue;
|
||||
auto s = processTable[i].state;
|
||||
if (s == ProcessState::Free) continue;
|
||||
target = i;
|
||||
break;
|
||||
}
|
||||
if (target < 0) {
|
||||
schedLock.Release();
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Fast path: target already Terminated -- harvest immediately.
|
||||
if (processTable[target].state == ProcessState::Terminated) {
|
||||
int code = processTable[target].exitCode;
|
||||
void* stackBase = (void*)processTable[target].stackBase;
|
||||
processTable[target].stackBase = 0;
|
||||
processTable[target].pml4Phys = 0;
|
||||
processTable[target].joinerSlot = -1;
|
||||
processTable[target].primarySlot = -1;
|
||||
processTable[target].state = ProcessState::Free;
|
||||
schedLock.Release();
|
||||
if (stackBase) Memory::g_pfa->Free(stackBase, StackPages);
|
||||
if (outExitCode) *outExitCode = code;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Block until the sibling terminates and wakes us.
|
||||
processTable[target].joinerSlot = callerSlot;
|
||||
processTable[callerSlot].state = ProcessState::Blocked;
|
||||
processTable[callerSlot].waitingOnObject = &processTable[target];
|
||||
processTable[callerSlot].waitingForPid = -1;
|
||||
processTable[callerSlot].sleepUntilTick = 0;
|
||||
processTable[callerSlot].runningOnCpu = -1;
|
||||
SwitchAwayFromBlockedCurrentLocked();
|
||||
|
||||
// Resumed -- harvest the sibling.
|
||||
schedLock.Acquire();
|
||||
int code = processTable[target].exitCode;
|
||||
void* stackBase = (void*)processTable[target].stackBase;
|
||||
processTable[target].stackBase = 0;
|
||||
processTable[target].pml4Phys = 0;
|
||||
processTable[target].joinerSlot = -1;
|
||||
processTable[target].primarySlot = -1;
|
||||
processTable[target].state = ProcessState::Free;
|
||||
schedLock.Release();
|
||||
if (stackBase) Memory::g_pfa->Free(stackBase, StackPages);
|
||||
if (outExitCode) *outExitCode = code;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int StartProcess(int pid) {
|
||||
if (pid < 0) return -1;
|
||||
|
||||
@@ -688,12 +961,30 @@ namespace Sched {
|
||||
}
|
||||
|
||||
int GetCurrentPid() {
|
||||
auto* cpu = Smp::GetCurrentCpuData();
|
||||
int slot = cpu->currentSlot;
|
||||
if (slot < 0) return -1;
|
||||
int primary = processTable[slot].primarySlot;
|
||||
if (primary < 0) primary = slot;
|
||||
return processTable[primary].pid;
|
||||
}
|
||||
|
||||
int GetCurrentTid() {
|
||||
auto* cpu = Smp::GetCurrentCpuData();
|
||||
int slot = cpu->currentSlot;
|
||||
return (slot >= 0) ? processTable[slot].pid : -1;
|
||||
}
|
||||
|
||||
Process* GetCurrentProcessPtr() {
|
||||
auto* cpu = Smp::GetCurrentCpuData();
|
||||
int slot = cpu->currentSlot;
|
||||
if (slot < 0) return nullptr;
|
||||
int primary = processTable[slot].primarySlot;
|
||||
if (primary < 0) primary = slot;
|
||||
return &processTable[primary];
|
||||
}
|
||||
|
||||
Process* GetCurrentThreadPtr() {
|
||||
auto* cpu = Smp::GetCurrentCpuData();
|
||||
int slot = cpu->currentSlot;
|
||||
if (slot < 0) return nullptr;
|
||||
@@ -708,10 +999,86 @@ namespace Sched {
|
||||
return;
|
||||
}
|
||||
|
||||
// If we're a sibling thread, this is a per-thread exit, not a
|
||||
// process exit. ExitCurrentThread does the right thing and never
|
||||
// returns.
|
||||
{
|
||||
int primary = processTable[slot].primarySlot;
|
||||
if (primary >= 0 && primary != slot) {
|
||||
ExitCurrentThread(0);
|
||||
}
|
||||
}
|
||||
|
||||
Process& proc = processTable[slot];
|
||||
proc.killPending = false;
|
||||
proc.startPending = false;
|
||||
int exitingPid = proc.pid;
|
||||
int primarySlot_ = slot;
|
||||
|
||||
// Drain sibling threads: any thread sharing our PML4 must stop using
|
||||
// it before we call FreeUserHalf. Ready/Blocked siblings can be
|
||||
// terminated immediately; siblings running on other CPUs are tagged
|
||||
// killPending and we spin until their tick handler routes them
|
||||
// through ExitCurrentThread.
|
||||
for (;;) {
|
||||
bool anyRunning = false;
|
||||
schedLock.Acquire();
|
||||
for (int i = 0; i < MaxProcesses; i++) {
|
||||
if (i == primarySlot_) continue;
|
||||
if (processTable[i].primarySlot != primarySlot_) continue;
|
||||
auto st = processTable[i].state;
|
||||
if (st == ProcessState::Free || st == ProcessState::Terminated) {
|
||||
continue;
|
||||
}
|
||||
if (st == ProcessState::Running) {
|
||||
processTable[i].killPending = true;
|
||||
anyRunning = true;
|
||||
continue;
|
||||
}
|
||||
// Ready or Blocked -- terminate inline, wake any joiner.
|
||||
if (st == ProcessState::Ready) readyCount--;
|
||||
processTable[i].state = ProcessState::Terminated;
|
||||
processTable[i].killPending = false;
|
||||
processTable[i].runningOnCpu = -1;
|
||||
processTable[i].waitingForPid = -1;
|
||||
processTable[i].sleepUntilTick = 0;
|
||||
processTable[i].waitingOnObject = nullptr;
|
||||
|
||||
void* obj = &processTable[i];
|
||||
for (int j = 0; j < MaxProcesses; j++) {
|
||||
if (processTable[j].state == ProcessState::Blocked &&
|
||||
processTable[j].waitingOnObject == obj) {
|
||||
processTable[j].state = ProcessState::Ready;
|
||||
readyCount++;
|
||||
processTable[j].waitingOnObject = nullptr;
|
||||
processTable[j].sleepUntilTick = 0;
|
||||
processTable[j].waitingForPid = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
schedLock.Release();
|
||||
if (!anyRunning) break;
|
||||
// Wait for the sibling CPU(s) to observe killPending on their
|
||||
// next timer tick. Briefly busy-wait; this path is rare.
|
||||
for (int spin = 0; spin < 1024; spin++) {
|
||||
asm volatile("pause");
|
||||
}
|
||||
}
|
||||
|
||||
// All siblings are quiescent. Reap any terminated sibling slots
|
||||
// (the process is gone, no joiner will arrive).
|
||||
for (int i = 0; i < MaxProcesses; i++) {
|
||||
if (i == primarySlot_) continue;
|
||||
if (processTable[i].primarySlot != primarySlot_) continue;
|
||||
if (processTable[i].state != ProcessState::Terminated) continue;
|
||||
void* stackBase = (void*)processTable[i].stackBase;
|
||||
processTable[i].stackBase = 0;
|
||||
processTable[i].pml4Phys = 0;
|
||||
processTable[i].primarySlot = -1;
|
||||
processTable[i].joinerSlot = -1;
|
||||
processTable[i].state = ProcessState::Free;
|
||||
if (stackBase) Memory::g_pfa->Free(stackBase, StackPages);
|
||||
}
|
||||
|
||||
// Clean up any windows owned by this process
|
||||
WinServer::CleanupProcess(exitingPid);
|
||||
@@ -817,98 +1184,53 @@ namespace Sched {
|
||||
|
||||
schedLock.Acquire();
|
||||
|
||||
// Find the process by PID
|
||||
int slot = -1;
|
||||
// pid identifies a process (main thread). Sibling-thread TIDs are
|
||||
// not killable through this entry point.
|
||||
int primarySlot_ = -1;
|
||||
for (int i = 0; i < MaxProcesses; i++) {
|
||||
if (processTable[i].pid == pid) {
|
||||
auto s = processTable[i].state;
|
||||
if (s == ProcessState::Ready || s == ProcessState::Running ||
|
||||
s == ProcessState::Blocked) {
|
||||
slot = i;
|
||||
}
|
||||
break;
|
||||
if (processTable[i].pid != pid) continue;
|
||||
if (processTable[i].primarySlot != i) continue;
|
||||
auto s = processTable[i].state;
|
||||
if (s == ProcessState::Ready || s == ProcessState::Running ||
|
||||
s == ProcessState::Blocked) {
|
||||
primarySlot_ = i;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (slot < 0) {
|
||||
if (primarySlot_ < 0) {
|
||||
schedLock.Release();
|
||||
return -1;
|
||||
}
|
||||
|
||||
Process& proc = processTable[slot];
|
||||
|
||||
if (proc.runningOnCpu >= 0) {
|
||||
// Process is currently running on another CPU. We cannot
|
||||
// safely free its resources (kernel stack, PML4, user pages)
|
||||
// because that CPU is actively using them. Set a kill-pending
|
||||
// flag; the target CPU's Tick() will call ExitProcess().
|
||||
proc.killPending = true;
|
||||
schedLock.Release();
|
||||
return 0;
|
||||
// Flag the main thread so its next tick (or scheduler dispatch)
|
||||
// routes through ExitProcess, which sweeps every sibling thread
|
||||
// and tears down the address space. If the main thread is parked
|
||||
// on a blocking syscall we promote it to Ready so the scheduler
|
||||
// picks it up promptly.
|
||||
Process& primary = processTable[primarySlot_];
|
||||
primary.killPending = true;
|
||||
if (primary.state == ProcessState::Blocked) {
|
||||
primary.state = ProcessState::Ready;
|
||||
readyCount++;
|
||||
primary.waitingForPid = -1;
|
||||
primary.waitingOnObject = nullptr;
|
||||
primary.sleepUntilTick = 0;
|
||||
}
|
||||
|
||||
// Process is Ready or Blocked (not running on any CPU).
|
||||
// Mark it non-runnable so the scheduler won't pick it up, but do not
|
||||
// expose it to the BSP reaper until teardown is complete.
|
||||
int killedPid = proc.pid;
|
||||
if (proc.state == ProcessState::Ready)
|
||||
readyCount--;
|
||||
proc.state = ProcessState::Terminated;
|
||||
proc.killPending = false;
|
||||
proc.startPending = false;
|
||||
proc.reapReady = false;
|
||||
proc.waitingForPid = -1;
|
||||
proc.sleepUntilTick = 0;
|
||||
proc.waitingOnObject = nullptr;
|
||||
|
||||
// Wake any processes blocked on this PID
|
||||
// Also stamp running siblings so they exit promptly; ExitProcess on
|
||||
// the main thread will additionally wait for them anyway.
|
||||
for (int i = 0; i < MaxProcesses; i++) {
|
||||
if (processTable[i].state == ProcessState::Blocked &&
|
||||
processTable[i].waitingForPid == killedPid) {
|
||||
processTable[i].state = ProcessState::Ready;
|
||||
readyCount++;
|
||||
processTable[i].waitingForPid = -1;
|
||||
processTable[i].waitingOnObject = nullptr;
|
||||
processTable[i].sleepUntilTick = 0;
|
||||
if (i == primarySlot_) continue;
|
||||
if (processTable[i].primarySlot != primarySlot_) continue;
|
||||
auto s = processTable[i].state;
|
||||
if (s == ProcessState::Running) {
|
||||
processTable[i].killPending = true;
|
||||
}
|
||||
}
|
||||
|
||||
schedLock.Release();
|
||||
KickOneIdleCpu(Smp::GetCurrentCpuData() ? Smp::GetCurrentCpuData()->cpuIndex : -1);
|
||||
|
||||
// Safe to clean up resources now -- process is not running anywhere.
|
||||
WinServer::CleanupProcess(killedPid);
|
||||
Drivers::Audio::Mixer::CleanupProcess(killedPid);
|
||||
Ipc::CleanupProcessSlot(slot, killedPid, proc.pml4Phys);
|
||||
Montauk::CleanupHeapForSlot(slot, proc.pml4Phys);
|
||||
Montauk::CleanupLibTable(slot);
|
||||
|
||||
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);
|
||||
|
||||
schedLock.Acquire();
|
||||
proc.reapReady = true;
|
||||
schedLock.Release();
|
||||
|
||||
// Kernel stack and PML4 freed by ReclaimTerminated on BSP tick.
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user