diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c466a8568..ec43cd069 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,3 +18,5 @@ jobs: secrets: inherit with: cpptest_enabled: true + build_params: all tests + nightly: true diff --git a/hal/aarch64/cpu.c b/hal/aarch64/cpu.c index 7b93a62f3..ccf95d1ef 100644 --- a/hal/aarch64/cpu.c +++ b/hal/aarch64/cpu.c @@ -83,7 +83,7 @@ int hal_cpuCreateContext(cpu_context_t **nctx, startFn_t start, void *kstack, si } -int hal_cpuPushSignal(void *kstack, void (*handler)(void), cpu_context_t *signalCtx, int n, unsigned int oldmask, const int src) +int hal_cpuPushSignal(void *kstack, void (*trampoline)(void), void (*handler)(int signo), cpu_context_t *signalCtx, int n, unsigned int oldmask, const int src) { cpu_context_t *ctx = (void *)((char *)kstack - sizeof(cpu_context_t)); const struct stackArg args[] = { @@ -92,6 +92,7 @@ int hal_cpuPushSignal(void *kstack, void (*handler)(void), cpu_context_t *signal { &ctx->pc, sizeof(ctx->pc) }, { &signalCtx, sizeof(signalCtx) }, { &oldmask, sizeof(oldmask) }, + { &handler, sizeof(handler) }, { &n, sizeof(n) }, }; @@ -100,7 +101,7 @@ int hal_cpuPushSignal(void *kstack, void (*handler)(void), cpu_context_t *signal hal_memcpy(signalCtx, ctx, sizeof(cpu_context_t)); /* parasoft-suppress-next-line MISRAC2012-RULE_11_1 "Program counter must be set to the address of the function" */ - signalCtx->pc = (u64)handler; + signalCtx->pc = (u64)trampoline; signalCtx->sp -= sizeof(cpu_context_t); hal_stackPutArgs((void **)&signalCtx->sp, sizeof(args) / sizeof(args[0]), args); diff --git a/hal/armv7a/cpu.c b/hal/armv7a/cpu.c index 7c5a6cf85..0286bb529 100644 --- a/hal/armv7a/cpu.c +++ b/hal/armv7a/cpu.c @@ -97,7 +97,7 @@ int hal_cpuCreateContext(cpu_context_t **nctx, startFn_t start, void *kstack, si } -int hal_cpuPushSignal(void *kstack, void (*handler)(void), cpu_context_t *signalCtx, int n, unsigned int oldmask, const int src) +int hal_cpuPushSignal(void *kstack, void (*trampoline)(void), void (*handler)(int signo), cpu_context_t *signalCtx, int n, unsigned int oldmask, const int src) { cpu_context_t *ctx = (void *)((char *)kstack - sizeof(cpu_context_t)); const struct stackArg args[] = { @@ -106,19 +106,20 @@ int hal_cpuPushSignal(void *kstack, void (*handler)(void), cpu_context_t *signal { &ctx->pc, sizeof(ctx->pc) }, { &signalCtx, sizeof(signalCtx) }, { &oldmask, sizeof(oldmask) }, + { &handler, sizeof(handler) }, { &n, sizeof(n) }, }; /* parasoft-suppress-next-line MISRAC2012-RULE_11_1 "Get address of function pointer as 32-bit number." */ - const u32 handler_addr = (u32)handler; + const u32 trampoline_addr = (u32)trampoline; (void)src; hal_memcpy(signalCtx, ctx, sizeof(cpu_context_t)); - signalCtx->pc = handler_addr & ~1U; + signalCtx->pc = trampoline_addr & ~1U; signalCtx->sp -= sizeof(cpu_context_t); - if ((handler_addr & 1U) != 0U) { + if ((trampoline_addr & 1U) != 0U) { signalCtx->psr |= THUMB_STATE; } else { diff --git a/hal/armv7m/cpu.c b/hal/armv7m/cpu.c index 9d1f99e69..c81b2b382 100644 --- a/hal/armv7m/cpu.c +++ b/hal/armv7m/cpu.c @@ -155,7 +155,7 @@ int hal_cpuCreateContext(cpu_context_t **nctx, startFn_t start, void *kstack, si } -int hal_cpuPushSignal(void *kstack, void (*handler)(void), cpu_context_t *signalCtx, int n, unsigned int oldmask, const int src) +int hal_cpuPushSignal(void *kstack, void (*trampoline)(void), void (*handler)(int signo), cpu_context_t *signalCtx, int n, unsigned int oldmask, const int src) { cpu_context_t *ctx = (void *)((char *)kstack - sizeof(cpu_context_t)); struct stackArg args[] = { @@ -164,6 +164,7 @@ int hal_cpuPushSignal(void *kstack, void (*handler)(void), cpu_context_t *signal { &ctx->hwctx.pc, sizeof(ctx->hwctx.pc) }, { &signalCtx, sizeof(signalCtx) }, { &oldmask, sizeof(oldmask) }, + { &handler, sizeof(handler) }, { &n, sizeof(n) }, { 0, 0 } /* Reserve space for optional HWCTX */ }; @@ -174,7 +175,7 @@ int hal_cpuPushSignal(void *kstack, void (*handler)(void), cpu_context_t *signal signalCtx->psp -= sizeof(cpu_context_t); /* parasoft-suppress-next-line MISRAC2012-RULE_11_1 "Need to assign function address to processor register" */ - signalCtx->hwctx.pc = (u32)handler; + signalCtx->hwctx.pc = (u32)trampoline; /* Set default PSR, clear potential ICI/IT flags */ signalCtx->hwctx.psr = 0x01000000U; diff --git a/hal/armv7r/cpu.c b/hal/armv7r/cpu.c index 34f26872f..3d8a0f9ec 100644 --- a/hal/armv7r/cpu.c +++ b/hal/armv7r/cpu.c @@ -96,7 +96,7 @@ int hal_cpuCreateContext(cpu_context_t **nctx, startFn_t start, void *kstack, si } -int hal_cpuPushSignal(void *kstack, void (*handler)(void), cpu_context_t *signalCtx, int n, unsigned int oldmask, const int src) +int hal_cpuPushSignal(void *kstack, void (*trampoline)(void), void (*handler)(int signo), cpu_context_t *signalCtx, int n, unsigned int oldmask, const int src) { cpu_context_t *ctx = (void *)((char *)kstack - sizeof(cpu_context_t)); const struct stackArg args[] = { @@ -105,6 +105,7 @@ int hal_cpuPushSignal(void *kstack, void (*handler)(void), cpu_context_t *signal { &ctx->pc, sizeof(ctx->pc) }, { &signalCtx, sizeof(signalCtx) }, { &oldmask, sizeof(oldmask) }, + { &handler, sizeof(handler) }, { &n, sizeof(n) }, }; @@ -113,10 +114,10 @@ int hal_cpuPushSignal(void *kstack, void (*handler)(void), cpu_context_t *signal hal_memcpy(signalCtx, ctx, sizeof(cpu_context_t)); /* parasoft-suppress-next-line MISRAC2012-RULE_11_1 "Program counter must be set to the address of the function" */ - signalCtx->pc = (u32)handler & ~0x1U; + signalCtx->pc = (u32)trampoline & ~0x1U; signalCtx->sp -= sizeof(cpu_context_t); /* parasoft-suppress-next-line MISRAC2012-RULE_11_1 "Checking in what processor mode code must be executed" */ - if (((u32)handler & 0x1U) != 0U) { + if (((u32)trampoline & 0x1U) != 0U) { signalCtx->psr |= THUMB_STATE; } else { diff --git a/hal/armv8m/cpu.c b/hal/armv8m/cpu.c index 8b19112e7..452d4140f 100644 --- a/hal/armv8m/cpu.c +++ b/hal/armv8m/cpu.c @@ -137,7 +137,7 @@ int hal_cpuCreateContext(cpu_context_t **nctx, startFn_t start, void *kstack, si } -int hal_cpuPushSignal(void *kstack, void (*handler)(void), cpu_context_t *signalCtx, int n, unsigned int oldmask, const int src) +int hal_cpuPushSignal(void *kstack, void (*trampoline)(void), void (*handler)(int signo), cpu_context_t *signalCtx, int n, unsigned int oldmask, const int src) { cpu_context_t *ctx = (void *)((char *)kstack - sizeof(cpu_context_t)); struct stackArg args[] = { @@ -146,6 +146,7 @@ int hal_cpuPushSignal(void *kstack, void (*handler)(void), cpu_context_t *signal { &ctx->hwctx.pc, sizeof(ctx->hwctx.pc) }, { &signalCtx, sizeof(signalCtx) }, { &oldmask, sizeof(oldmask) }, + { &handler, sizeof(handler) }, { &n, sizeof(n) }, { 0U, 0U } /* Reserve space for optional HWCTX */ }; @@ -155,7 +156,7 @@ int hal_cpuPushSignal(void *kstack, void (*handler)(void), cpu_context_t *signal signalCtx->psp -= sizeof(cpu_context_t); /* parasoft-suppress-next-line MISRAC2012-RULE_11_1 "Need to assign function address to processor register" */ - signalCtx->hwctx.pc = (u32)handler; + signalCtx->hwctx.pc = (u32)trampoline; /* Set default PSR, clear potential ICI/IT flags */ signalCtx->hwctx.psr = DEFAULT_PSR; diff --git a/hal/armv8r/cpu.c b/hal/armv8r/cpu.c index 8458ed70b..8cac5dded 100644 --- a/hal/armv8r/cpu.c +++ b/hal/armv8r/cpu.c @@ -96,7 +96,7 @@ int hal_cpuCreateContext(cpu_context_t **nctx, startFn_t start, void *kstack, si } -int hal_cpuPushSignal(void *kstack, void (*handler)(void), cpu_context_t *signalCtx, int n, unsigned int oldmask, const int src) +int hal_cpuPushSignal(void *kstack, void (*trampoline)(void), void (*handler)(int signo), cpu_context_t *signalCtx, int n, unsigned int oldmask, const int src) { cpu_context_t *ctx = (void *)((char *)kstack - sizeof(cpu_context_t)); const struct stackArg args[] = { @@ -105,19 +105,20 @@ int hal_cpuPushSignal(void *kstack, void (*handler)(void), cpu_context_t *signal { &ctx->pc, sizeof(ctx->pc) }, { &signalCtx, sizeof(signalCtx) }, { &oldmask, sizeof(oldmask) }, + { &handler, sizeof(handler) }, { &n, sizeof(n) }, }; /* parasoft-suppress-next-line MISRAC2012-RULE_11_1 "Program counter must be set to the address of the function" */ - u32 handler_addr = (u32)handler; + u32 trampoline_addr = (u32)trampoline; (void)src; hal_memcpy(signalCtx, ctx, sizeof(cpu_context_t)); - signalCtx->pc = handler_addr & ~1U; + signalCtx->pc = trampoline_addr & ~1U; signalCtx->sp -= sizeof(cpu_context_t); - if ((handler_addr & 1U) != 0U) { + if ((trampoline_addr & 1U) != 0U) { signalCtx->psr |= THUMB_STATE; } else { diff --git a/hal/cpu.h b/hal/cpu.h index 4b0467d4d..d3dfd5f93 100644 --- a/hal/cpu.h +++ b/hal/cpu.h @@ -108,7 +108,7 @@ int hal_cpuSupervisorMode(cpu_context_t *ctx); /* oldmask: mask to be restored in sigreturn after handling the signal */ -int hal_cpuPushSignal(void *kstack, void (*handler)(void), cpu_context_t *signalCtx, int n, unsigned int oldmask, const int src); +int hal_cpuPushSignal(void *kstack, void (*trampoline)(void), void (*handler)(int signo), cpu_context_t *signalCtx, int n, unsigned int oldmask, const int src); void hal_cpuSigreturn(void *kstack, void *ustack, cpu_context_t **ctx); diff --git a/hal/ia32/cpu.c b/hal/ia32/cpu.c index d398317b4..383641f21 100644 --- a/hal/ia32/cpu.c +++ b/hal/ia32/cpu.c @@ -173,7 +173,7 @@ int hal_cpuCreateContext(cpu_context_t **nctx, startFn_t start, void *kstack, si } -int hal_cpuPushSignal(void *kstack, void (*handler)(void), cpu_context_t *signalCtx, int n, unsigned int oldmask, const int src) +int hal_cpuPushSignal(void *kstack, void (*trampoline)(void), void (*handler)(int signo), cpu_context_t *signalCtx, int n, unsigned int oldmask, const int src) { cpu_context_t *ctx = (void *)((char *)kstack - sizeof(cpu_context_t)); const struct stackArg args[] = { @@ -182,6 +182,7 @@ int hal_cpuPushSignal(void *kstack, void (*handler)(void), cpu_context_t *signal { &signalCtx, sizeof(signalCtx) }, { &oldmask, sizeof(oldmask) }, { &n, sizeof(n) }, + { &handler, sizeof(handler) }, }; (void)src; @@ -189,7 +190,7 @@ int hal_cpuPushSignal(void *kstack, void (*handler)(void), cpu_context_t *signal hal_memcpy(signalCtx, ctx, sizeof(cpu_context_t)); /* parasoft-suppress-next-line MISRAC2012-RULE_11_1 "Need to assign function address to processor register" */ - signalCtx->eip = (u32)handler; + signalCtx->eip = (u32)trampoline; signalCtx->esp -= sizeof(cpu_context_t); hal_stackPutArgs((void **)&signalCtx->esp, sizeof(args) / sizeof(args[0]), args); diff --git a/hal/riscv64/cpu.c b/hal/riscv64/cpu.c index 1d01166be..9d321f6ff 100644 --- a/hal/riscv64/cpu.c +++ b/hal/riscv64/cpu.c @@ -198,7 +198,7 @@ int hal_cpuCreateContext(cpu_context_t **nctx, startFn_t start, void *kstack, si } -int hal_cpuPushSignal(void *kstack, void (*handler)(void), cpu_context_t *signalCtx, int n, unsigned int oldmask, const int src) +int hal_cpuPushSignal(void *kstack, void (*trampoline)(void), void (*handler)(int signo), cpu_context_t *signalCtx, int n, unsigned int oldmask, const int src) { cpu_context_t *ctx = (void *)((char *)kstack - sizeof(cpu_context_t)); const struct stackArg args[] = { @@ -206,6 +206,7 @@ int hal_cpuPushSignal(void *kstack, void (*handler)(void), cpu_context_t *signal { &ctx->sepc, sizeof(ctx->sepc) }, { &signalCtx, sizeof(signalCtx) }, { &oldmask, sizeof(oldmask) }, + { &handler, sizeof(handler) }, { &n, sizeof(n) }, }; @@ -214,7 +215,7 @@ int hal_cpuPushSignal(void *kstack, void (*handler)(void), cpu_context_t *signal hal_memcpy(signalCtx, ctx, sizeof(cpu_context_t)); /* parasoft-suppress-next-line MISRAC2012-RULE_11_1 "Need to assign function address to processor register" */ - signalCtx->sepc = (u64)handler; + signalCtx->sepc = (u64)trampoline; signalCtx->sp -= sizeof(cpu_context_t); hal_stackPutArgs((void **)&signalCtx->sp, sizeof(args) / sizeof(args[0]), args); diff --git a/hal/sparcv8leon/cpu.c b/hal/sparcv8leon/cpu.c index 9ab77f0ec..c9dc1df9b 100644 --- a/hal/sparcv8leon/cpu.c +++ b/hal/sparcv8leon/cpu.c @@ -151,7 +151,7 @@ void _hal_cpuSetKernelStack(void *kstack) } -int hal_cpuPushSignal(void *kstack, void (*handler)(void), cpu_context_t *signalCtx, int n, unsigned int oldmask, const int src) +int hal_cpuPushSignal(void *kstack, void (*trampoline)(void), void (*handler)(int signo), cpu_context_t *signalCtx, int n, unsigned int oldmask, const int src) { cpu_context_t *ctx = (void *)((char *)kstack - sizeof(cpu_context_t)); const struct stackArg args[] = { @@ -161,13 +161,14 @@ int hal_cpuPushSignal(void *kstack, void (*handler)(void), cpu_context_t *signal { &ctx->pc, sizeof(ctx->pc) }, { &signalCtx, sizeof(signalCtx) }, { &oldmask, sizeof(oldmask) }, + { &handler, sizeof(handler) }, { &n, sizeof(n) }, }; hal_memcpy(signalCtx, ctx, sizeof(cpu_context_t)); /* parasoft-begin-suppress MISRAC2012-RULE_11_1 "Need to assign function address to processor register" */ - signalCtx->pc = (u32)handler; - signalCtx->npc = (u32)handler + 4U; + signalCtx->pc = (u32)trampoline; + signalCtx->npc = (u32)trampoline + 4U; /* parasoft-end-suppress MISRAC2012-RULE_11_1 */ signalCtx->sp -= sizeof(cpu_context_t); diff --git a/include/signal.h b/include/signal.h index 39a6a57f7..956bdba8d 100644 --- a/include/signal.h +++ b/include/signal.h @@ -17,8 +17,108 @@ #ifndef _PH_SIGNAL_H_ #define _PH_SIGNAL_H_ -enum { signal_kill = 1, signal_segv, signal_illegal, signal_cancel = 32 }; +#include "types.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef void (*sighandler_t)(int signo); + + +#define SIGNULL 0 +#define SIGHUP 1 +#define SIGINT 2 +#define SIGQUIT 3 +#define SIGILL 4 +#define SIGTRAP 5 +#define SIGABRT 6 +#define SIGIOT SIGABRT +#define SIGEMT 7 +#define SIGFPE 8 +#define SIGKILL 9 +#define SIGBUS 10 +#define SIGSEGV 11 +#define SIGSYS 12 +#define SIGPIPE 13 +#define SIGALRM 14 +#define SIGTERM 15 +#define SIGURG 16 +#define SIGSTOP 17 +#define SIGTSTP 18 +#define SIGCONT 19 +#define SIGCHLD 20 +#define SIGTTIN 21 +#define SIGTTOU 22 +#define SIGIO 23 +#define SIGXCPU 24 +#define SIGXFSZ 25 +#define SIGVTALRM 26 +#define SIGPROF 27 +#define SIGWINCH 28 +#define SIGINFO 29 +#define SIGUSR1 30 +#define SIGUSR2 31 +#define PH_SIGCANCEL 32 #define NSIG 32 +/* clang-format off */ +#define SIG_DFL ((sighandler_t)0) +#define SIG_IGN ((sighandler_t)-1) +#define SIG_ERR ((sighandler_t)-2) +/* clang-format on */ + + +enum { SIG_BLOCK, + SIG_SETMASK, + SIG_UNBLOCK }; + + +#define SA_NOCLDSTOP (1U << 0) +#define SA_NOCLDWAIT (1U << 1) +#define SA_NODEFER (1U << 2) +#define SA_ONSTACK (1U << 3) +#define SA_RESETHAND (1U << 4) +#define SA_RESTART (1U << 5) +#define SA_RESTORER (1U << 6) +#define SA_SIGINFO (1U << 7) + + +typedef unsigned int sigset_t; +typedef int sig_atomic_t; + + +union sigval { + int sival_int; + void *sival_ptr; +}; + + +typedef struct { + int si_signo; + int si_code; + pid_t si_pid; + uid_t si_uid; + void *si_addr; + int si_status; + union sigval si_value; +} siginfo_t; + + +struct sigaction { + union { + sighandler_t sa_handler; + void (*sa_sigaction)(int signo, siginfo_t *info, void *context); + }; + sigset_t sa_mask; + int sa_flags; +}; + +#ifdef __cplusplus +} +#endif + #endif diff --git a/include/syscalls.h b/include/syscalls.h index b4c1a066d..0a3491cf7 100644 --- a/include/syscalls.h +++ b/include/syscalls.h @@ -66,8 +66,7 @@ ID(sys_perf_stop) \ ID(syspageprog) \ ID(va2pa) \ - ID(signalHandle) \ - ID(signalPost) \ + ID(signalAction) \ ID(signalMask) \ ID(signalSuspend) \ ID(priority) \ diff --git a/main.c b/main.c index 84dace1b8..9ed31c995 100644 --- a/main.c +++ b/main.c @@ -48,6 +48,9 @@ static void main_initthr(void *unused) _hal_start(); _usrv_start(); + /* Disable "killing" init thread */ + proc_current()->sigmask = ~0U; + lib_printf("main: Starting syspage programs:"); syspage_progShow(); diff --git a/posix/posix_private.h b/posix/posix_private.h index 7b73e4fe6..2eb7d1519 100644 --- a/posix/posix_private.h +++ b/posix/posix_private.h @@ -26,43 +26,6 @@ #define US_PORT 0xffffffffU /* FIXME */ -#define SIGHUP 1 -#define SIGINT 2 -#define SIGQUIT 3 -#define SIGILL 4 -#define SIGTRAP 5 -#define SIGABRT 6 -#define SIGIOT SIGABRT -#define SIGEMT 7 -#define SIGFPE 8 -#define SIGKILL 9 -#define SIGBUS 10 -#define SIGSEGV 11 -#define SIGSYS 12 -#define SIGPIPE 13 -#define SIGALRM 14 -#define SIGTERM 15 -#define SIGURG 16 -#define SIGSTOP 17 -#define SIGTSTP 18 -#define SIGCONT 19 -#define SIGCHLD 20 -#define SIGTTIN 21 -#define SIGTTOU 22 -#define SIGIO 23 -#define SIGXCPU 24 -#define SIGXFSZ 25 -#define SIGVTALRM 26 -#define SIGPROF 27 -#define SIGWINCH 28 -#define SIGINFO 29 -#define SIGUSR1 30 -#define SIGUSR2 31 - -#define SIG_ERR (-1) -#define SIG_DFL (-2) -#define SIG_IGN (-3) - #define HOST_NAME_MAX 255U diff --git a/proc/process.c b/proc/process.c index d43861161..9f8bf60e2 100644 --- a/proc/process.c +++ b/proc/process.c @@ -32,11 +32,6 @@ #include "userintr.h" #include "perf/trace-events.h" -/* Process states */ -#define PREFORK 0 -#define FORKING 1 -#define FORKED 2 - typedef struct _process_spawn_t { spinlock_t sl; thread_t *wq; @@ -113,6 +108,7 @@ static void process_destroy(process_t *p) vm_kfree(ghost); } + vm_kfree(p->sigactions); vm_kfree(p->path); vm_kfree(p->argv); vm_kfree(p->envp); @@ -211,7 +207,7 @@ int proc_start(startFn_t start, void *arg, const char *path) process->ports = NULL; process->sigpend = 0; - process->sighandler = NULL; + process->sigactions = NULL; process->tls.tls_base = 0; process->tls.tbss_sz = 0; process->tls.tdata_sz = 0; @@ -242,12 +238,6 @@ int proc_start(startFn_t start, void *arg, const char *path) } -void proc_kill(process_t *proc) -{ - proc_threadsDestroy(&proc->threads, NULL); -} - - void process_dumpException(unsigned int n, exc_context_t *ctx) { thread_t *thread; @@ -292,7 +282,7 @@ static void process_exception(unsigned int n, exc_context_t *ctx) hal_cpuHalt(); } - (void)threads_sigpost(thread->process, thread, signal_kill); + (void)threads_sigpost(thread->process, thread, SIGKILL); /* Don't allow current thread to return to the userspace, * it will crash anyway. */ @@ -311,7 +301,11 @@ static void process_illegal(unsigned int n, exc_context_t *ctx) hal_cpuHalt(); } - (void)threads_sigpost(process, thread, signal_illegal); + (void)threads_sigpost(process, thread, SIGILL); + + if (thread->exit != 0U) { + proc_threadEnd(); + } } @@ -1346,33 +1340,45 @@ static void process_restoreParentKstack(thread_t *current, thread_t *parent) } -__attribute__((noreturn)) static void proc_vforkedExit(thread_t *current, process_spawn_t *spawn, int state) +void proc_vforkedDied(thread_t *thread, int state) { - current->ustack = NULL; - proc_changeMap(current->process, NULL, NULL, NULL); + spinlock_ctx_t sc; + process_spawn_t *spawn = thread->execdata; - proc_kill(current->process); + thread->execdata = NULL; + thread->ustack = NULL; + proc_changeMap(thread->process, NULL, NULL, NULL); + + proc_kill(thread->process); /* Only possible in the case of `initthread` exit or failure to fork. */ if (spawn->parent == NULL) { hal_spinlockDestroy(&spawn->sl); (void)vm_objectPut(spawn->object); - - proc_threadEnd(); } else { - process_restoreParentKstack(current, spawn->parent); + process_restoreParentKstack(thread, spawn->parent); - proc_spawnThreadEnd(spawn, state); + hal_spinlockSet(&spawn->sl, &sc); + spawn->state = state; + (void)proc_threadWakeup(&spawn->wq); + hal_spinlockClear(&spawn->sl, &sc); } } +__attribute__((noreturn)) static void proc_vforkedExit(thread_t *current, int state) +{ + proc_vforkedDied(current, state); + proc_threadEnd(); +} + + void proc_exit(int code) { thread_t *current = proc_current(); process_spawn_t *spawn = current->execdata; - arg_t args[3]; + arg_t args[2]; current->process->exit = code; @@ -1384,10 +1390,9 @@ void proc_exit(int code) } args[0] = (arg_t)current; - args[1] = (arg_t)spawn; - args[2] = (arg_t)FORKED; + args[1] = (arg_t)FORKED; /* parasoft-suppress-next-line MISRAC2012-RULE_11_1 "Function can accept two different types of first argument" */ - hal_jmp(proc_vforkedExit, current->kstack + current->kstacksz, NULL, 3, args); + hal_jmp(proc_vforkedExit, current->kstack + current->kstacksz, NULL, 2, args); } proc_kill(current->process); @@ -1411,7 +1416,11 @@ static void process_vforkThread(void *arg) /* POSIX: A child created via fork inherits a copy of its parent's signal mask */ current->sigmask = parent->sigmask; - current->process->sighandler = parent->process->sighandler; + + ret = proc_cloneSigactions(parent->process, current->process); + if (ret < 0) { + proc_spawnThreadEnd(spawn, ret); + } hal_spinlockSet(&spawn->sl, &sc); while (spawn->state < FORKING) { @@ -1623,7 +1632,7 @@ int proc_fork(void) #ifndef NOMMU thread_t *current, *parent; unsigned int sigmask; - arg_t args[3]; + arg_t args[2]; err = proc_vfork(); if (err == 0) { @@ -1649,10 +1658,9 @@ int proc_fork(void) if (err < 0) { args[0] = (arg_t)current; - args[1] = (arg_t)current->execdata; - args[2] = (arg_t)err; + args[1] = (arg_t)err; /* parasoft-suppress-next-line MISRAC2012-RULE_11_1 "Function can accept two different types of first argument" */ - hal_jmp(proc_vforkedExit, (unsigned char *)current->kstack + current->kstacksz, NULL, 3, args); + hal_jmp(proc_vforkedExit, (unsigned char *)current->kstack + current->kstacksz, NULL, 2, args); } else { hal_cpuEnableInterrupts(); @@ -1668,6 +1676,7 @@ static int process_execve(thread_t *current) process_spawn_t *spawn = current->execdata; thread_t *parent = spawn->parent; vm_map_t *map, *imap; + int i, keep; /* The old user stack is no longer valid */ current->ustack = NULL; @@ -1705,9 +1714,26 @@ static int process_execve(thread_t *current) current->parentkstack = NULL; current->execdata = NULL; - current->process->sighandler = NULL; current->process->sigpend = 0; + /* POSIX: signals ignored by the calling process should remain ignored */ + if (current->process->sigactions != NULL) { + keep = 0; + for (i = 1; i < NSIG; ++i) { + /* parasoft-suppress-next-line MISRAC2012-RULE_11_1-a "POSIX compliant definition" */ + if (current->process->sigactions[i - 1].sa_handler == SIG_IGN) { + keep = 1; + } + else { + current->process->sigactions[i - 1].sa_handler = SIG_DFL; + } + } + if (keep == 0) { + vm_kfree(current->process->sigactions); + current->process->sigactions = NULL; + } + } + /* Close cloexec file descriptors */ (void)posix_exec(); diff --git a/proc/process.h b/proc/process.h index 535fb0cf5..00596c43b 100644 --- a/proc/process.h +++ b/proc/process.h @@ -18,6 +18,7 @@ #define _PH_PROC_PROCESS_H_ #include "hal/hal.h" +#include "include/signal.h" #include "vm/vm.h" #include "lock.h" #include "vm/amap.h" @@ -26,8 +27,13 @@ #define MAX_PID MAX_ID +/* Process states */ +#define PREFORK 0 +#define FORKING 1 +#define FORKED 2 -typedef void (*sighandlerFn_t)(void); + +typedef void (*sigtrampolineFn_t)(void); typedef struct _process_t { @@ -62,7 +68,8 @@ typedef struct _process_t { idtree_t resources; unsigned int sigpend; - sighandlerFn_t sighandler; + sigtrampolineFn_t sigtrampoline; + struct sigaction *sigactions; /* indices are offset by 1, as signal 0 is invalid */ void *got; hal_tls_t tls; @@ -114,6 +121,9 @@ int proc_sigpost(int pid, int sig); int proc_vfork(void); +void proc_vforkedDied(struct _thread_t *thread, int state); + + int proc_fork(void); diff --git a/proc/threads.c b/proc/threads.c index d174fc92c..11611fd99 100644 --- a/proc/threads.c +++ b/proc/threads.c @@ -41,6 +41,13 @@ const struct lockAttr proc_lockAttrDefault = { .type = PH_LOCK_NORMAL }; /* Special empty queue value used to wakeup next enqueued thread. This is used to implement sticky conditions */ static thread_t *const wakeupPending = (void *)-1; +/* Signal default actions */ +enum { + SIGNAL_TERMINATE = 0, + SIGNAL_TERMINATE_THREAD, + SIGNAL_IGNORE, +}; + static struct { vm_map_t *kmap; spinlock_t spinlock; @@ -260,6 +267,11 @@ static void thread_destroy(thread_t *thread) while (thread->locks != NULL) { proc_lockForceUnlock(thread->locks, UNLOCK_DO_YIELD); } + + if (thread->execdata != NULL) { + thread->kstack = thread->execkstack; + proc_vforkedDied(thread, FORKED); + } vm_kfree(thread->kstack); process = thread->process; @@ -812,21 +824,29 @@ void proc_threadDestroy(thread_t *t) } -void proc_threadsDestroy(thread_t **threads, const thread_t *except) +static void _proc_threadsDestroy(thread_t **threads, const thread_t *except) { thread_t *t; - spinlock_ctx_t sc; - hal_spinlockSet(&threads_common.spinlock, &sc); t = *threads; if (t != NULL) { do { if (t != except) { _proc_threadExit(t); } + /* parasoft-suppress-next-line MISRAC2012-DIR_4_1 "procnext is never NULL, and *threads is checked earlier" */ t = t->procnext; } while (t != *threads); } +} + + +void proc_threadsDestroy(thread_t **threads, const thread_t *except) +{ + spinlock_ctx_t sc; + + hal_spinlockSet(&threads_common.spinlock, &sc); + _proc_threadsDestroy(threads, except); hal_spinlockClear(&threads_common.spinlock, &sc); } @@ -848,6 +868,15 @@ void proc_reap(void) } +void proc_kill(process_t *proc) +{ + spinlock_ctx_t sc; + hal_spinlockSet(&threads_common.spinlock, &sc); + _proc_threadsDestroy(&proc->threads, NULL); + hal_spinlockClear(&threads_common.spinlock, &sc); +} + + void proc_changeMap(process_t *proc, vm_map_t *map, vm_map_t *imap, pmap_t *pmap) { spinlock_ctx_t sc; @@ -1279,42 +1308,99 @@ static time_t _proc_nextWakeup(void) */ -int threads_sigpost(process_t *process, thread_t *thread, int sig) +static int threads_sigmutable(int sig) { - spinlock_ctx_t sc; - u32 sigbit; + switch (sig) { + /* POSIX: SIGKILL and SIGSTOP cannot be caught or ignored */ + case SIGKILL: + case SIGSTOP: + case PH_SIGCANCEL: + case SIGNULL: + return 0; + default: + return ((sig < 0) || (sig > NSIG)) ? 0 : 1; + } +} + +static int _threads_sigdefault(process_t *process, thread_t *thread, int sig) +{ switch (sig) { - case signal_segv: - /* parasoft-suppress-next-line MISRAC2012-RULE_16_1 MISRAC2012-RULE_16_3 "Intentional fall-through" */ - case signal_illegal: - if (process->sighandler != NULL) { - break; + case SIGHUP: + case SIGINT: + case SIGQUIT: + case SIGILL: + case SIGTRAP: + case SIGABRT: /* And SIGIOT */ + case SIGEMT: + case SIGFPE: + case SIGBUS: + case SIGSEGV: + case SIGSYS: + case SIGPIPE: + case SIGALRM: + case SIGTERM: + case SIGIO: + case SIGXCPU: + case SIGXFSZ: + case SIGVTALRM: + case SIGPROF: + case SIGUSR1: + case SIGUSR2: + case SIGKILL: + process->exit = sig * (int)(1UL << 8U); + _proc_threadsDestroy(&process->threads, NULL); + return SIGNAL_TERMINATE; + + case SIGURG: + case SIGCHLD: + case SIGWINCH: + case SIGINFO: + case SIGCONT: /* TODO: Continue process. */ + case SIGTSTP: /* TODO: Stop process. */ + case SIGTTIN: /* TODO: Stop process. */ + case SIGTTOU: /* TODO: Stop process. */ + case SIGSTOP: /* TODO: Stop process. */ + case SIGNULL: + return SIGNAL_IGNORE; + + case PH_SIGCANCEL: + if (thread != NULL) { + _proc_threadExit(thread); } + return SIGNAL_TERMINATE_THREAD; - /* Fall-through */ - case signal_kill: - proc_kill(process); - return EOK; + default: + return -EINVAL; + } +} - case signal_cancel: - proc_threadDestroy(thread); - return EOK; - case 0: - return EOK; +int threads_sigpost(process_t *process, thread_t *thread, int sig) +{ + u32 sigbit; + spinlock_ctx_t sc; - default: - /* Handles any value of 'sig' not covered by the case labels. */ - break; - } + hal_spinlockSet(&threads_common.spinlock, &sc); - if ((sig < 0) || (sig >= NSIG)) { + if ((sig < 0) || (sig > NSIG)) { + hal_spinlockClear(&threads_common.spinlock, &sc); return -EINVAL; } - sigbit = (u32)1U << (unsigned int)sig; - hal_spinlockSet(&threads_common.spinlock, &sc); + if (sig == PH_SIGCANCEL || sig == SIGNULL) { + (void)_threads_sigdefault(process, thread, sig); + hal_spinlockClear(&threads_common.spinlock, &sc); + return EOK; + } + + /* parasoft-suppress-next-line MISRAC2012-RULE_11_1-a "POSIX compliant definition" */ + if ((process->sigactions != NULL) && (process->sigactions[sig - 1].sa_handler == SIG_IGN)) { + hal_spinlockClear(&threads_common.spinlock, &sc); + return EOK; + } + + sigbit = (u32)1U << (unsigned int)sig; if (thread != NULL) { thread->sigpend |= sigbit; @@ -1326,10 +1412,6 @@ int threads_sigpost(process_t *process, thread_t *thread, int sig) if (thread != NULL) { do { if ((sigbit & ~thread->sigmask) != 0U) { - if (thread->interruptible != 0U) { - _thread_interrupt(thread); - } - break; } thread = thread->procnext; @@ -1345,7 +1427,19 @@ int threads_sigpost(process_t *process, thread_t *thread, int sig) } } - (void)hal_cpuReschedule(&threads_common.spinlock, &sc); + if ((sigbit & ~thread->sigmask) != 0U) { + if (thread->interruptible != 0U) { + _thread_interrupt(thread); + } + + if ((process->sigactions == NULL) || (process->sigactions[sig - 1].sa_handler == SIG_DFL)) { + (void)_threads_sigdefault(process, thread, sig); + thread->sigpend &= ~sigbit; + process->sigpend &= ~sigbit; + } + } + + hal_spinlockClear(&threads_common.spinlock, &sc); return EOK; } @@ -1356,14 +1450,45 @@ static int _threads_checkSignal(thread_t *selected, process_t *proc, cpu_context #ifndef KERNEL_SIGNALS_DISABLE unsigned int sig; + sighandler_t handler; + int defaultAction; sig = (selected->sigpend | proc->sigpend) & ~selected->sigmask; - if ((sig != 0U) && (proc->sighandler != NULL)) { + while (sig != 0U) { sig = hal_cpuGetLastBit(sig); + handler = (proc->sigactions == NULL) ? SIG_DFL : proc->sigactions[sig - 1U].sa_handler; + + if (handler == SIG_DFL) { + defaultAction = _threads_sigdefault(proc, selected, (int)sig); + } + else { + defaultAction = -1; + } + + if ((defaultAction == SIGNAL_TERMINATE) || (defaultAction == SIGNAL_TERMINATE_THREAD)) { + return -1; + } + + /* parasoft-suppress-next-line MISRAC2012-RULE_11_1-a "POSIX compliant definition" */ + if ((handler == SIG_IGN) || (defaultAction == SIGNAL_IGNORE) || (defaultAction == -EINVAL)) { + selected->sigpend &= ~(u32)(1UL << sig); + proc->sigpend &= ~(u32)(1UL << sig); + + /* Check for other signals */ + sig = (selected->sigpend | proc->sigpend) & ~selected->sigmask; + continue; + } + + /* POSIX: sa_mask should be ORed with current process signal mask */ + selected->sigmask |= proc->sigactions[sig - 1U].sa_mask; + if (((unsigned int)proc->sigactions[sig - 1U].sa_flags & SA_NODEFER) == 0U) { + selected->sigmask |= (u32)(1UL << sig); + } + /* TODO: Handle other sa_flags */ - if (hal_cpuPushSignal(selected->kstack + selected->kstacksz, proc->sighandler, signalCtx, (int)sig, oldmask, src) == 0) { - selected->sigpend &= ~(0x1U << sig); - proc->sigpend &= ~(0x1U << sig); + if (hal_cpuPushSignal(selected->kstack + selected->kstacksz, proc->sigtrampoline, handler, signalCtx, (int)sig, oldmask, src) == 0) { + selected->sigpend &= ~(u32)(1UL << sig); + proc->sigpend &= ~(u32)(1UL << sig); return 0; } } @@ -1374,6 +1499,102 @@ static int _threads_checkSignal(thread_t *selected, process_t *proc, cpu_context } +int threads_setSigaction(int sig, sigtrampolineFn_t trampoline, const struct sigaction *act, struct sigaction *old) +{ + process_t *process; + struct sigaction *sa = NULL; + spinlock_ctx_t sc; + + if ((sig <= 0) || (sig >= NSIG)) { + return -EINVAL; + } + + if ((act != NULL) && (threads_sigmutable(sig) == 0)) { + return -EINVAL; + } + + hal_spinlockSet(&threads_common.spinlock, &sc); + process = _proc_current()->process; + + /* allocate sigactions array if required */ + if ((act != NULL) && (process->sigactions == NULL) && (act->sa_handler != SIG_DFL)) { + hal_spinlockClear(&threads_common.spinlock, &sc); + sa = vm_kmalloc(sizeof(struct sigaction) * (u8)(NSIG - 1)); + if (sa == NULL) { + return -ENOMEM; + } + + hal_spinlockSet(&threads_common.spinlock, &sc); + /* for a running process this array should never get freed, but allocation race can happen here */ + if (process->sigactions == NULL) { + hal_memset(sa, 0, sizeof(struct sigaction) * (u8)(NSIG - 1)); + process->sigactions = sa; + sa = NULL; + } + } + + if (old != NULL) { + /* sigactions can be null if act.sa_handler == SIG_DFL */ + if (process->sigactions == NULL) { + old->sa_handler = SIG_DFL; + old->sa_flags = 0; + old->sa_mask = 0; + } + else { + hal_memcpy(old, &process->sigactions[sig - 1], sizeof(struct sigaction)); + } + } + + /* sigactions can be null if act.sa_handler == SIG_DFL */ + if ((act != NULL) && (process->sigactions != NULL)) { + hal_memcpy(&process->sigactions[sig - 1], act, sizeof(struct sigaction)); + } + + if (trampoline != NULL) { + process->sigtrampoline = trampoline; + } + + hal_spinlockClear(&threads_common.spinlock, &sc); + if (sa != NULL) { + vm_kfree(sa); + } + return 0; +} + + +int proc_cloneSigactions(process_t *parent, process_t *child) +{ + spinlock_ctx_t sc; + int i; + + /* In case of one of parent threads is updating signal handlers */ + hal_spinlockSet(&threads_common.spinlock, &sc); + + if (parent->sigactions != NULL) { + for (i = 1; i < NSIG; ++i) { + if (parent->sigactions[i - 1].sa_handler == SIG_DFL) { + continue; + } + + hal_spinlockClear(&threads_common.spinlock, &sc); + child->sigactions = vm_kmalloc(sizeof(struct sigaction) * (u8)(NSIG - 1)); + if (child->sigactions == NULL) { + return -ENOMEM; + } + + hal_spinlockSet(&threads_common.spinlock, &sc); + hal_memcpy(child->sigactions, parent->sigactions, sizeof(struct sigaction) * (u8)(NSIG - 1)); + break; + } + } + + child->sigtrampoline = parent->sigtrampoline; + + hal_spinlockClear(&threads_common.spinlock, &sc); + return 0; +} + + void threads_setupUserReturn(void *retval, cpu_context_t *ctx) { spinlock_ctx_t sc; @@ -1391,7 +1612,7 @@ void threads_setupUserReturn(void *retval, cpu_context_t *ctx) if (_threads_checkSignal(thread, thread->process, signalCtx, thread->sigmask, SIG_SRC_SCALL) == 0) { /* parasoft-suppress-next-line MISRAC2012-RULE_11_1 "f is passed to function hal_jmp which need void * type" */ - f = thread->process->sighandler; + f = thread->process->sigtrampoline; hal_spinlockClear(&threads_common.spinlock, &sc); hal_jmp(f, kstackTop, hal_cpuGetUserSP(signalCtx), 0, NULL); /* no return */ @@ -1426,12 +1647,19 @@ int threads_sigsuspend(unsigned int mask) /* check for pending signals before sleep - with the new mask */ if (_threads_checkSignal(thread, thread->process, signalCtx, oldmask, SIG_SRC_SCALL) == 0) { /* parasoft-suppress-next-line MISRAC2012-RULE_11_1 "f is passed to function hal_jmp which need void * type" */ - f = thread->process->sighandler; + f = thread->process->sigtrampoline; hal_spinlockClear(&threads_common.spinlock, &sc); hal_jmp(f, kstackTop, hal_cpuGetUserSP(signalCtx), 0, NULL); /* no return */ } + /* check if thread wasn't killed by signal */ + if (thread->exit != 0U) { + hal_spinlockClear(&threads_common.spinlock, &sc); + proc_threadEnd(); + /* no return */ + } + /* Sleep forever (atomic lock release), interruptible */ thread_t *tqueue = NULL; _proc_threadEnqueue(&tqueue, 0, 1); @@ -1442,7 +1670,7 @@ int threads_sigsuspend(unsigned int mask) hal_spinlockSet(&threads_common.spinlock, &sc); if (_threads_checkSignal(thread, thread->process, signalCtx, oldmask, SIG_SRC_SCALL) == 0) { /* parasoft-suppress-next-line MISRAC2012-RULE_11_1 "f is passed to function hal_jmp which need void * type" */ - f = thread->process->sighandler; + f = thread->process->sigtrampoline; hal_spinlockClear(&threads_common.spinlock, &sc); hal_jmp(f, kstackTop, hal_cpuGetUserSP(signalCtx), 0, NULL); /* no return */ diff --git a/proc/threads.h b/proc/threads.h index 72b2b8f80..f316239c2 100644 --- a/proc/threads.h +++ b/proc/threads.h @@ -186,4 +186,10 @@ int threads_sigsuspend(unsigned int mask); void threads_setupUserReturn(void *retval, cpu_context_t *ctx); +int threads_setSigaction(int sig, void (*trampoline)(void), const struct sigaction *act, struct sigaction *old); + + +int proc_cloneSigactions(process_t *parent, process_t *child); + + #endif diff --git a/syscalls.c b/syscalls.c index 7387da10e..bf7730fab 100644 --- a/syscalls.c +++ b/syscalls.c @@ -236,9 +236,13 @@ int syscalls_spawnSyspage(u8 *ustack) int syscalls_sys_exit(u8 *ustack) { int code; + unsigned int maskedCode; GETFROMSTACK(ustack, int, code, 0U); - proc_exit(code); + + maskedCode = (unsigned int)code & 0xffU; + proc_exit((int)maskedCode); + return EOK; } @@ -1015,63 +1019,39 @@ addr_t syscalls_va2pa(u8 *ustack) } -int syscalls_signalHandle(u8 *ustack) -{ - sighandlerFn_t handler; - thread_t *thread; - - GETFROMSTACK(ustack, sighandlerFn_t, handler, 0U); - - thread = proc_current(); - thread->process->sighandler = handler; - - return EOK; -} - - -int syscalls_signalPost(u8 *ustack) +int syscalls_signalAction(u8 *ustack) { - int pid, tid, signal, err; - process_t *proc; - thread_t *t = NULL; - - GETFROMSTACK(ustack, int, pid, 0U); - GETFROMSTACK(ustack, int, tid, 1U); - GETFROMSTACK(ustack, int, signal, 2U); + process_t *proc = proc_current()->process; + int sig; + struct sigaction *act; + struct sigaction *old; + sigtrampolineFn_t trampoline; - proc = proc_find(pid); - if (proc == NULL) { - return -EINVAL; - } + GETFROMSTACK(ustack, int, sig, 0U); + GETFROMSTACK(ustack, struct sigaction *, act, 1U); + GETFROMSTACK(ustack, struct sigaction *, old, 2U); + GETFROMSTACK(ustack, sigtrampolineFn_t, trampoline, 3U); - if (tid >= 0) { - t = threads_findThread(tid); - if (t == NULL) { - (void)proc_put(proc); - return -EINVAL; - } + if ((act != NULL) && (vm_mapBelongs(proc, act, sizeof(*act)) < 0)) { + return -EFAULT; } - if ((t != NULL) && (t->process != proc)) { - (void)proc_put(proc); - threads_put(t); - return -EINVAL; + if ((old != NULL) && (vm_mapBelongs(proc, old, sizeof(*old)) < 0)) { + return -EFAULT; } - err = threads_sigpost(proc, t, signal); - - (void)proc_put(proc); - if (t != NULL) { - threads_put(t); + /* parasoft-suppress-next-line MISRAC2012-RULE_11_1 "Use of common address verification routine" */ + if ((trampoline != NULL) && (vm_mapBelongs(proc, (void *)trampoline, 1U) < 0)) { + return -EFAULT; } - return err; + return threads_setSigaction(sig, trampoline, act, old); } unsigned int syscalls_signalMask(u8 *ustack) { - unsigned int mask, mmask, old; + unsigned int mask, mmask, old, new; thread_t *t; GETFROMSTACK(ustack, unsigned int, mask, 0U); @@ -1080,7 +1060,14 @@ unsigned int syscalls_signalMask(u8 *ustack) t = proc_current(); old = t->sigmask; - t->sigmask = (mask & mmask) | (t->sigmask & ~mmask); + new = (mask & mmask) | (old & ~mmask); + + /* POSIX: It is not possible to block those signals which cannot be ignored. + * This shall be enforced by the system without causing an error to be indicated. + */ + new &= ~(u32)((1UL << SIGKILL) | (1UL << SIGSTOP)); + + t->sigmask = new; return old; } @@ -1968,12 +1955,15 @@ void *syscalls_dispatch(int n, u8 *ustack, cpu_context_t *ctx) trace_eventSyscallExit(n, proc_getTid(thread)); + if (thread->exit == 0U) { + threads_setupUserReturn(retval, ctx); + } + + /* setupUserReturn could deliver a terminating signal */ if (thread->exit != 0U) { proc_threadEnd(); } - threads_setupUserReturn(retval, ctx); - return retval; } diff --git a/vm/map.c b/vm/map.c index 240b6cf3e..2584036c8 100644 --- a/vm/map.c +++ b/vm/map.c @@ -832,7 +832,11 @@ static void map_pageFault(unsigned int n, exc_context_t *ctx) hal_cpuHalt(); } - (void)threads_sigpost(thread->process, thread, signal_segv); + (void)threads_sigpost(thread->process, thread, SIGSEGV); + } + + if (thread->exit != 0U) { + proc_threadEnd(); } } #endif