Files
nt-lite/code/posix/posix_proc.c
T

124 lines
3.8 KiB
C

// posix_proc.c - posix_spawn, waitpid, getpid
#include <stddef.h>
#include <string.h>
#include <syscall.h>
#include "posix.h"
#include "posix_path.h"
// pid -> proc handle table (user-mode side, for waitpid)
#define PROC_TABLE_SIZE 32
typedef struct {
pid_t pid;
uint32_t handle;
bool used;
} ProcEntry;
static ProcEntry gProcTable[PROC_TABLE_SIZE];
static void ProcTableInsert(pid_t pid, uint32_t handle) {
for (int i = 0; i < PROC_TABLE_SIZE; i++) {
if (!gProcTable[i].used) {
gProcTable[i] = (ProcEntry){ pid, handle, true };
return;
}
}
SysCloseHandle(handle);
}
static uint32_t ProcTableFind(pid_t pid) {
for (int i = 0; i < PROC_TABLE_SIZE; i++)
if (gProcTable[i].used && gProcTable[i].pid == pid)
return gProcTable[i].handle;
return 0;
}
static void ProcTableRemove(pid_t pid) {
for (int i = 0; i < PROC_TABLE_SIZE; i++)
if (gProcTable[i].used && gProcTable[i].pid == pid)
gProcTable[i].used = false;
}
// Build a flat Windows-style cmdline from a NULL-terminated argv array.
// Each token that contains a space is wrapped in double-quotes.
// argv[0] is included (it becomes the executable token visible to _start).
static void BuildCmdline(char* const argv[], char* out, size_t outSize) {
size_t pos = 0;
for (int i = 0; argv && argv[i]; i++) {
if (i > 0 && pos < outSize - 1) out[pos++] = ' ';
const char* tok = argv[i];
bool needQuote = false;
for (const char* c = tok; *c; c++) if (*c == ' ' || *c == '\t') { needQuote = true; break; }
if (needQuote && pos < outSize - 1) out[pos++] = '"';
for (; *tok && pos < outSize - 2; tok++) {
if (*tok == '"') { out[pos++] = '\\'; }
out[pos++] = *tok;
}
if (needQuote && pos < outSize - 1) out[pos++] = '"';
}
if (pos < outSize) out[pos] = '\0';
}
// ---------------------------------------------------------------------------
// POSIX API
// ---------------------------------------------------------------------------
__declspec(dllexport) pid_t getpid(void) {
return (pid_t)SysGetCurrentPid();
}
__declspec(dllexport) int posix_spawn(pid_t* pidOut,
const char* path,
const posix_spawn_file_actions_t* file_actions, // ignored v1
const posix_spawnattr_t* attrp, // ignored v1
char* const argv[],
char* const envp[]) // ignored v1
{
(void)file_actions; (void)attrp; (void)envp;
char native[512];
PosixTranslatePath(path, native, sizeof(native));
char cmdline[512];
BuildCmdline(argv, cmdline, sizeof(cmdline));
// If argv was NULL or empty, fall back to just the path so _start still
// gets a meaningful argv[0].
if (cmdline[0] == '\0') {
size_t len = strlen(path);
if (len >= sizeof(cmdline)) len = sizeof(cmdline) - 1;
memcpy(cmdline, path, len);
cmdline[len] = '\0';
}
uint32_t procHandle;
uint32_t s = SysCreateProcess(native, &procHandle, cmdline);
if (s != 0) { errno = ENOENT; return -1; }
uint32_t kpid = 0;
SysGetProcessPid(procHandle, &kpid);
ProcTableInsert((pid_t)kpid, procHandle);
if (pidOut) *pidOut = (pid_t)kpid;
return 0;
}
// options: WNOHANG not supported in v1 (always blocks).
__declspec(dllexport) pid_t waitpid(pid_t pid, int* status, int options) {
(void)options;
uint32_t handle = ProcTableFind(pid);
if (!handle) { errno = ESRCH; return -1; }
SysWaitForProcess(handle);
int exitCode = 0;
SysGetProcessExitCode(handle, &exitCode);
if (status) *status = exitCode << 8; // WEXITSTATUS convention
SysCloseHandle(handle);
ProcTableRemove(pid);
return pid;
}
__declspec(dllexport) void exit(int status) {
SysExitProcess(status);
}