/* * Process.hpp * SYS_EXIT, SYS_YIELD, SYS_SLEEP_MS, SYS_GETPID, * SYS_WAITPID, SYS_SPAWN, SYS_GETARGS, SYS_PROCLIST, SYS_KILL syscalls * Copyright (c) 2026 Daniel Hammer */ #pragma once #include #include #include #include #include #include #include "Syscall.hpp" #include "Common.hpp" #include "WinServer.hpp" #include "Path.hpp" namespace montauk::abi { static void Sys_Exit(int exitCode) { (void)exitCode; Sched::ExitProcess(); } static void Sys_Yield() { Sched::Schedule(); } static void Sys_SleepMs(uint64_t ms) { Sched::BlockForSleep(ms); } static int Sys_GetPid() { return Sched::GetCurrentPid(); } static void Sys_WaitPid(int pid) { Sched::BlockOnPid(pid); } static int Sys_Spawn(const char* path, const char* args) { char resolved[256]; if (!ResolveProcessPath(path, resolved, sizeof(resolved))) return -1; auto* parent = Sched::GetCurrentProcessPtr(); int parentSlot = Ipc::CurrentSlot(); bool inheritRedirection = parent && parent->redirected; int childPid = Sched::Spawn(resolved, args, !inheritRedirection); if (childPid < 0) return childPid; if (inheritRedirection) { auto* child = Sched::GetProcessByPid(childPid); int childSlot = Ipc::SlotForPid(childPid); if (child == nullptr || childSlot < 0 || parentSlot < 0) { Sched::KillProcess(childPid); return -1; } child->ioOutHandle = DuplicateHandleBetweenSlots(parentSlot, parent->ioOutHandle, childSlot); child->ioInHandle = DuplicateHandleBetweenSlots(parentSlot, parent->ioInHandle, childSlot); child->ioKeyHandle = DuplicateHandleBetweenSlots(parentSlot, parent->ioKeyHandle, childSlot); if (child->ioOutHandle < 0 || child->ioInHandle < 0 || child->ioKeyHandle < 0 || !ConfigureRedirWaitsetForSlot(childSlot, child)) { Sched::KillProcess(childPid); return -1; } child->redirected = true; child->parentPid = parent->pid; child->termCols = parent->termCols; child->termRows = parent->termRows; if (Sched::StartProcess(childPid) < 0) { Sched::KillProcess(childPid); return -1; } } return childPid; } static int Sys_GetArgs(char* buf, uint64_t maxLen) { auto* proc = Sched::GetCurrentProcessPtr(); if (proc == nullptr || buf == nullptr || maxLen == 0) return -1; int i = 0; for (; i < (int)maxLen - 1 && proc->args[i]; i++) { buf[i] = proc->args[i]; } buf[i] = '\0'; return i; } static int Sys_ProcList(ProcInfo* buf, int maxCount) { if (buf == nullptr || maxCount <= 0) return 0; int count = 0; for (int i = 0; i < Sched::MaxProcesses && count < maxCount; i++) { auto* proc = Sched::GetProcessSlot(i); if (!proc || proc->state == Sched::ProcessState::Free) continue; // Skip sibling-thread slots; only show one entry per process. if (proc->primarySlot != i) continue; buf[count].pid = (int32_t)proc->pid; buf[count].parentPid = (int32_t)proc->parentPid; buf[count].state = (uint8_t)proc->state; buf[count]._pad[0] = 0; buf[count]._pad[1] = 0; buf[count]._pad[2] = 0; { int j = 0; for (; j < 63 && proc->name[j]; j++) buf[count].name[j] = proc->name[j]; buf[count].name[j] = '\0'; } buf[count].heapUsed = Sched::g_allocatedPages[i] * 0x1000; buf[count].cpuTimeMs = proc->cpuTimeMs; count++; } return count; } static int Sys_Kill(int pid) { return Sched::KillProcess(pid); } static int Sys_SetUser(int pid, const char* name) { if (name == nullptr) return -1; auto* target = Sched::GetProcessByPid(pid); if (target == nullptr) return -1; int i = 0; for (; i < 31 && name[i]; i++) target->user[i] = name[i]; target->user[i] = '\0'; return 0; } static int Sys_GetUser(char* buf, uint64_t maxLen) { auto* proc = Sched::GetCurrentProcessPtr(); if (proc == nullptr || buf == nullptr || maxLen == 0) return -1; int i = 0; for (; i < (int)maxLen - 1 && proc->user[i]; i++) buf[i] = proc->user[i]; buf[i] = '\0'; return i; } static int Sys_GetCwd(char* buf, uint64_t maxLen) { auto* proc = Sched::GetCurrentProcessPtr(); if (proc == nullptr || buf == nullptr || maxLen == 0) return -1; const char* cwd = proc->cwd[0] ? proc->cwd : "0:/"; int i = 0; for (; i < (int)maxLen - 1 && cwd[i]; i++) buf[i] = cwd[i]; buf[i] = '\0'; return i; } // ==================================================================== // Threading // ==================================================================== static int Sys_ThreadSpawn(uint64_t entry, uint64_t arg, uint64_t userStackTop) { return Sched::SpawnThread(entry, arg, userStackTop); } [[noreturn]] static void Sys_ThreadExit(int exitCode) { Sched::ExitCurrentThread(exitCode); } static int Sys_ThreadJoin(int tid, int* outExitCode) { return Sched::JoinThread(tid, outExitCode); } static int Sys_ThreadSelf() { return Sched::GetCurrentTid(); } static int Sys_Chdir(const char* path) { auto* proc = Sched::GetCurrentProcessPtr(); if (proc == nullptr || path == nullptr) return -1; char resolved[256]; if (!ResolveProcessPath(path, resolved, sizeof(resolved))) return -1; bool isDriveRoot = false; { int prefixLen = 0; if (ParseDrivePrefix(resolved, &prefixLen) >= 0 && resolved[prefixLen] == '/' && resolved[prefixLen + 1] == '\0') { isDriveRoot = true; } } if (isDriveRoot) { const char* entries[1]; if (Fs::Vfs::VfsReadDir(resolved, entries, 1) < 0) return -1; } else { Fs::Vfs::BackendFile file = {-1, -1, 0}; if (Fs::Vfs::OpenBackendFile(resolved, file) < 0) return -1; Fs::Vfs::CloseBackendFile(file); } int i = 0; for (; i < 255 && resolved[i]; i++) proc->cwd[i] = resolved[i]; proc->cwd[i] = '\0'; return 0; } };