From 2339e3b7cdcc6fd812fa5179f5d3eeabba84196a Mon Sep 17 00:00:00 2001 From: Tulio A M Mendes Date: Sat, 14 Feb 2026 21:58:29 -0300 Subject: [PATCH] feat: posix_spawn syscall (atomic fork+execve) - SYSCALL_POSIX_SPAWN = 96 - Combines fork + execve in one syscall call - Returns 0 to parent, stores child PID via user pointer - Child exits with 127 if execve fails - 35/35 smoke tests pass, cppcheck clean --- include/syscall.h | 1 + src/kernel/syscall.c | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/include/syscall.h b/include/syscall.h index 0e82963..3baebe9 100644 --- a/include/syscall.h +++ b/include/syscall.h @@ -119,6 +119,7 @@ enum { SYSCALL_GETITIMER = 93, SYSCALL_WAITID = 94, SYSCALL_SIGQUEUE = 95, + SYSCALL_POSIX_SPAWN = 96, }; #endif diff --git a/src/kernel/syscall.c b/src/kernel/syscall.c index e4d0421..a4b6dbe 100644 --- a/src/kernel/syscall.c +++ b/src/kernel/syscall.c @@ -2318,6 +2318,45 @@ void syscall_handler(struct registers* regs) { return; } + if (syscall_no == SYSCALL_POSIX_SPAWN) { + /* posix_spawn(pid_t* pid_out, path, argv, envp) + * Combines fork+execve atomically. Returns 0 on success and stores + * child pid in *pid_out. The child immediately execs path. */ + uint32_t* user_pid = (uint32_t*)sc_arg0(regs); + const char* path = (const char*)sc_arg1(regs); + const char* const* argv = (const char* const*)sc_arg2(regs); + const char* const* envp = (const char* const*)sc_arg3(regs); + + if (user_pid && user_range_ok(user_pid, 4) == 0) { + sc_ret(regs) = (uint32_t)-EFAULT; return; + } + + /* Fork: creates child with copy of parent's regs */ + int child_pid = syscall_fork_impl(regs); + if (child_pid < 0) { + sc_ret(regs) = (uint32_t)child_pid; return; + } + if (child_pid == 0) { + /* We are in the child — exec immediately */ + int rc = syscall_execve_impl(regs, path, argv, envp); + if (rc < 0) { + /* execve failed — exit child */ + process_exit_notify(127); + hal_cpu_enable_interrupts(); + schedule(); + for (;;) hal_cpu_idle(); + } + return; /* execve rewrote regs, return to new program */ + } + /* Parent: store child PID */ + if (user_pid) { + uint32_t cpid = (uint32_t)child_pid; + (void)copy_to_user(user_pid, &cpid, 4); + } + sc_ret(regs) = 0; + return; + } + if (syscall_no == SYSCALL_POLL) { struct pollfd* fds = (struct pollfd*)sc_arg0(regs); uint32_t nfds = sc_arg1(regs); -- 2.43.0