]> xenbits.xensource.com Git - unikraft/unikraft.git/commitdiff
lib/posix-process/signal: Add signal delivery
authorMichalis Pappas <michalis@unikraft.io>
Wed, 3 Jan 2024 11:36:37 +0000 (12:36 +0100)
committerUnikraft Bot <monkey@unikraft.io>
Wed, 26 Mar 2025 08:05:34 +0000 (08:05 +0000)
Implement signal delivery. Signals are delivered at syscall exit
by registering a handler to the syscall shim. The same handler
could be potentially register a handler to a preemptive scheduler's
context switch.

Notable differences from Linux:
- The Core disposition falls back to Term, as we don't support
  application core dumps.
- The Stop and Cont dispositions are ignored, as these are normally
  relevant to shells.

Checkpatch-Ignore: LONG_LINE
Signed-off-by: Michalis Pappas <michalis@unikraft.io>
Reviewed-by: Ioan-Teodor Teugea <ioan_teodor.teugea@stud.acs.upb.ro>
Reviewed-by: Sergiu Moga <sergiu@unikraft.io>
Reviewed-by: Andrei Tatar <andrei@unikraft.io>
Approved-by: Andrei Tatar <andrei@unikraft.io>
GitHub-Closes: #1248

lib/posix-process/Makefile.uk
lib/posix-process/arch/arm64/signal.S [new file with mode: 0644]
lib/posix-process/arch/arm64/ucontext.c [new file with mode: 0644]
lib/posix-process/arch/x86_64/signal.S [new file with mode: 0644]
lib/posix-process/arch/x86_64/ucontext.c [new file with mode: 0644]
lib/posix-process/signal/deliver.c [new file with mode: 0644]
lib/posix-process/signal/signal.h

index 5dda200df7e9a9fd800b441f6dca90d74e864125..15e6b05f15f1edf754c5b870c1bd6779aeab86ab 100644 (file)
@@ -19,6 +19,9 @@ LIBPOSIX_PROCESS_SRCS-y += $(LIBPOSIX_PROCESS_BASE)/process.c
 LIBPOSIX_PROCESS_SRCS-y += $(LIBPOSIX_PROCESS_BASE)/wait.c
 
 LIBPOSIX_PROCESS_SRCS-$(CONFIG_LIBPOSIX_PROCESS_SIGNAL) += $(LIBPOSIX_PROCESS_BASE)/signal/signal.c
+LIBPOSIX_PROCESS_SRCS-$(CONFIG_LIBPOSIX_PROCESS_SIGNAL) += $(LIBPOSIX_PROCESS_BASE)/arch/$(CONFIG_UK_ARCH)/ucontext.c
+LIBPOSIX_PROCESS_SRCS-$(CONFIG_LIBPOSIX_PROCESS_SIGNAL) += $(LIBPOSIX_PROCESS_BASE)/arch/$(CONFIG_UK_ARCH)/signal.S|arch
+LIBPOSIX_PROCESS_SRCS-$(CONFIG_LIBPOSIX_PROCESS_SIGNAL) += $(LIBPOSIX_PROCESS_BASE)/signal/deliver.c
 LIBPOSIX_PROCESS_SRCS-y += $(LIBPOSIX_PROCESS_BASE)/signal/sigaltstack.c
 LIBPOSIX_PROCESS_SRCS-y += $(LIBPOSIX_PROCESS_BASE)/signal/rt_sigpending.c
 LIBPOSIX_PROCESS_SRCS-y += $(LIBPOSIX_PROCESS_BASE)/signal/rt_sigprocmask.c
diff --git a/lib/posix-process/arch/arm64/signal.S b/lib/posix-process/arch/arm64/signal.S
new file mode 100644 (file)
index 0000000..3cc5878
--- /dev/null
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/* Copyright (c) 2025, Unikraft GmbH and The Unikraft Authors.
+ * Licensed under the BSD-3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ */
+
+#include <uk/asm.h>
+
+/* Switch to application stack and call signal handler.
+ * Switch back to UK stack before return.
+ *
+ * void pprocess_signal_call_handler_with_stack(int signum, siginfo_t *si,
+ *                                              ucontext_t *ctx, void *handler,
+ *                                              void *sp);
+ *
+ * Notice: Parameters to handler already saved to registers
+ *         via this function's first four parameters.
+ */
+ENTRY(pprocess_signal_call_handler_with_stack)
+       str     x19, [sp], #16  /* save x19 before we corrupt */
+       mov     x19, sp         /* save uk sp */
+       mov     sp, x4          /* switch to handler sp */
+       blr     x3              /* call handler */
+       mov     sp, x19         /* switch back to uk sp */
+       ldr     x19, [sp], #16  /* restore x19 */
+       ret
diff --git a/lib/posix-process/arch/arm64/ucontext.c b/lib/posix-process/arch/arm64/ucontext.c
new file mode 100644 (file)
index 0000000..20821f7
--- /dev/null
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/* Copyright (c) 2023, Unikraft GmbH and The Unikraft Authors.
+ * Licensed under the BSD-3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ */
+
+#include <signal.h>
+#include <string.h>
+
+#include <uk/essentials.h>
+#include <uk/syscall.h>
+
+void pprocess_signal_arch_set_ucontext(struct ukarch_execenv *execenv,
+                                      ucontext_t *ucontext)
+{
+       UK_ASSERT(execenv);
+       UK_ASSERT(ucontext);
+
+       memcpy(&ucontext->uc_mcontext.regs, &execenv->regs.x,
+              ARRAY_SIZE(ucontext->uc_mcontext.regs));
+
+       /* TODO Populate the rest of the context */
+}
+
+void pprocess_signal_arch_get_ucontext(ucontext_t *ucontext,
+                                      struct ukarch_execenv *execenv)
+{
+       UK_ASSERT(ucontext);
+       UK_ASSERT(execenv);
+
+       memcpy(&execenv->regs.x, &ucontext->uc_mcontext.regs,
+              ARRAY_SIZE(ucontext->uc_mcontext.regs));
+
+       /* TODO Populate the rest of the context */
+}
diff --git a/lib/posix-process/arch/x86_64/signal.S b/lib/posix-process/arch/x86_64/signal.S
new file mode 100644 (file)
index 0000000..8a6c8bc
--- /dev/null
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/* Copyright (c) 2025, Unikraft GmbH and The Unikraft Authors.
+ * Licensed under the BSD-3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ */
+
+#include <uk/asm.h>
+
+/* Switch to application stack and call signal handler.
+ * Switch back to UK stack before return.
+ *
+ * void pprocess_signal_call_handler_with_stack(int signum, siginfo_t *si,
+ *                                              ucontext_t *ctx, void *handler,
+ *                                              void *sp);
+ *
+ * Notice: Parameters to handler already saved to registers
+ *         via this function's first four parameters.
+ */
+ENTRY(pprocess_signal_call_handler_with_stack)
+       push    %rbp            /* save rbp before we corrupt */
+       movq    %rsp, %rbp      /* save uk sp */
+       movq    %r8, %rsp       /* switch to handler sp */
+       call    *%rcx           /* call handler */
+       movq    %rbp, %rsp      /* switch back to uk sp */
+       pop     %rbp            /* restore rbp */
+       ret
diff --git a/lib/posix-process/arch/x86_64/ucontext.c b/lib/posix-process/arch/x86_64/ucontext.c
new file mode 100644 (file)
index 0000000..90fa6a8
--- /dev/null
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/* Copyright (c) 2023, Unikraft GmbH and The Unikraft Authors.
+ * Licensed under the BSD-3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ */
+
+#define _GNU_SOURCE
+#include <signal.h>
+
+#include <uk/syscall.h>
+
+void pprocess_signal_arch_set_ucontext(struct ukarch_execenv *execenv,
+                                      ucontext_t *ucontext)
+{
+       UK_ASSERT(execenv);
+       UK_ASSERT(ucontext);
+
+       ucontext->uc_mcontext.gregs[REG_R8] = execenv->regs.r8;
+       ucontext->uc_mcontext.gregs[REG_R9] = execenv->regs.r9;
+       ucontext->uc_mcontext.gregs[REG_R10] = execenv->regs.r10;
+       ucontext->uc_mcontext.gregs[REG_R11] = execenv->regs.r11;
+       ucontext->uc_mcontext.gregs[REG_R12] = execenv->regs.r12;
+       ucontext->uc_mcontext.gregs[REG_R13] = execenv->regs.r13;
+       ucontext->uc_mcontext.gregs[REG_R14] = execenv->regs.r14;
+       ucontext->uc_mcontext.gregs[REG_R15] = execenv->regs.r15;
+       ucontext->uc_mcontext.gregs[REG_RDI] = execenv->regs.rdi;
+       ucontext->uc_mcontext.gregs[REG_RSI] = execenv->regs.rsi;
+       ucontext->uc_mcontext.gregs[REG_RBP] = execenv->regs.rbp;
+       ucontext->uc_mcontext.gregs[REG_RBX] = execenv->regs.rbx;
+       ucontext->uc_mcontext.gregs[REG_RDX] = execenv->regs.rdx;
+       ucontext->uc_mcontext.gregs[REG_RAX] = execenv->regs.rax;
+       ucontext->uc_mcontext.gregs[REG_RCX] = execenv->regs.rcx;
+       ucontext->uc_mcontext.gregs[REG_RSP] = execenv->regs.rsp;
+       ucontext->uc_mcontext.gregs[REG_RIP] = execenv->regs.rip;
+
+       /* TODO Populate the rest of the context */
+}
+
+void pprocess_signal_arch_get_ucontext(ucontext_t *ucontext,
+                                      struct ukarch_execenv *execenv)
+{
+       UK_ASSERT(ucontext);
+       UK_ASSERT(execenv);
+
+       execenv->regs.r8 = ucontext->uc_mcontext.gregs[REG_R8];
+       execenv->regs.r9 = ucontext->uc_mcontext.gregs[REG_R9];
+       execenv->regs.r10 = ucontext->uc_mcontext.gregs[REG_R10];
+       execenv->regs.r11 = ucontext->uc_mcontext.gregs[REG_R11];
+       execenv->regs.r12 = ucontext->uc_mcontext.gregs[REG_R12];
+       execenv->regs.r13 = ucontext->uc_mcontext.gregs[REG_R13];
+       execenv->regs.r14 = ucontext->uc_mcontext.gregs[REG_R14];
+       execenv->regs.r15 = ucontext->uc_mcontext.gregs[REG_R15];
+       execenv->regs.rdi = ucontext->uc_mcontext.gregs[REG_RDI];
+       execenv->regs.rsi = ucontext->uc_mcontext.gregs[REG_RSI];
+       execenv->regs.rbp = ucontext->uc_mcontext.gregs[REG_RBP];
+       execenv->regs.rbx = ucontext->uc_mcontext.gregs[REG_RBX];
+       execenv->regs.rdx = ucontext->uc_mcontext.gregs[REG_RDX];
+       execenv->regs.rax = ucontext->uc_mcontext.gregs[REG_RAX];
+       execenv->regs.rcx = ucontext->uc_mcontext.gregs[REG_RCX];
+       execenv->regs.rsp = ucontext->uc_mcontext.gregs[REG_RSP];
+       execenv->regs.rip = ucontext->uc_mcontext.gregs[REG_RIP];
+
+       /* TODO Populate the rest of the context */
+}
+
diff --git a/lib/posix-process/signal/deliver.c b/lib/posix-process/signal/deliver.c
new file mode 100644 (file)
index 0000000..4babee8
--- /dev/null
@@ -0,0 +1,381 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/* Copyright (c) 2023, Unikraft GmbH and The Unikraft Authors.
+ * Licensed under the BSD-3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ */
+
+#include <uk/essentials.h>
+#include <uk/prio.h>
+#include <uk/process.h>
+#include <uk/syscall.h>
+
+#include "sigset.h"
+#include "signal.h"
+#include "siginfo.h"
+
+/* asm */
+void pprocess_signal_call_handler_with_stack(int signum, siginfo_t *si,
+                                            ucontext_t *ctx, void *handler,
+                                            void *sp);
+
+static void uk_sigact_term(int __unused sig)
+{
+       uk_pr_warn("tid %d terminated by signal\n", uk_sys_gettid());
+       uk_posix_process_kill(uk_thread_current());
+}
+
+static void uk_sigact_ign(int __unused sig)
+{
+       UK_BUG(); /* We should never reach this point */
+}
+
+static void uk_sigact_core(int __unused sig)
+{
+       uk_pr_warn("%d: SIG_CORE not supported, falling back to SIG_TERM\n",
+                  sig);
+       uk_sigact_term(sig);
+}
+
+static void uk_sigact_stop(int __unused sig)
+{
+       uk_pr_warn("SIG_STOP not supported\n");
+}
+
+static void uk_sigact_cont(int __unused sig)
+{
+       uk_pr_warn("SIG_CONT not supported\n");
+}
+
+bool pprocess_signal_is_deliverable(struct posix_thread *pthread, int signum)
+{
+       struct posix_process *proc;
+
+       UK_ASSERT(pthread);
+       UK_ASSERT(signum);
+
+       proc = tid2pprocess(pthread->tid);
+       UK_ASSERT(proc);
+
+       return (!IS_MASKED(pthread, signum) && !IS_IGNORED(proc, signum));
+}
+
+/* Switches to application context and jumps to handler.
+ * Restores uk context on return.
+ */
+static
+void jmp_handler(struct ukarch_execenv *execenv, int signum, siginfo_t *si,
+                ucontext_t *ctx, void *handler, void *sp)
+{
+       struct ukarch_sysctx uk_sysctx;
+
+       ukarch_sysctx_store(&uk_sysctx);
+       ukarch_sysctx_load(&execenv->sysctx);
+
+       /* Notice: We implement this trampoline in asm as there is a ton of
+        *         challenges involved with correctly preserving context
+        *         with inline asm.
+        */
+       pprocess_signal_call_handler_with_stack(signum, si, ctx, handler, sp);
+
+       ukarch_sysctx_load(&uk_sysctx);
+}
+
+static void handle_self(struct uk_signal *sig, const struct kern_sigaction *ks,
+                       struct ukarch_execenv *execenv)
+{
+       ucontext_t ucontext __maybe_unused;
+       struct posix_process *this_process;
+       struct ukarch_auxspcb *auxspcb;
+       __uptr fp, saved_fp;
+       stack_t *altstack;
+       __uptr ulsp;
+
+       UK_ASSERT(sig);
+       UK_ASSERT(ks);
+       UK_ASSERT(execenv);
+
+       this_process = uk_pprocess_current();
+       UK_ASSERT(this_process);
+
+       altstack = &this_process->signal->altstack;
+
+       uk_pr_debug("tid %d handling signal %d, handler: 0x%lx, flags: 0x%lx\n",
+                   uk_sys_gettid(), sig->siginfo.si_signo,
+                   (__u64)ks->ks_handler,
+                   ks->ks_flags);
+
+       /* TODO: Make sure sigaltstack() does not modify the altstack state
+        * while we are executing on it, neither sigaction() modifies
+        * sa_flags->SA_ONSTACK.
+        */
+
+       if ((ks->ks_flags & SA_ONSTACK) && !(altstack->ss_flags & SS_DISABLE)) {
+               UK_ASSERT(altstack->ss_sp);
+               UK_ASSERT(!(altstack->ss_flags & SS_ONSTACK));
+
+               altstack->ss_flags |= SS_ONSTACK;
+
+               uk_pr_debug("Using altstack, ss_sp: 0x%lx, ss_size: 0x%lx\n",
+                           (__u64)altstack->ss_sp, altstack->ss_size);
+
+               ulsp = ukarch_gen_sp(altstack->ss_sp, altstack->ss_size);
+       } else {
+               ulsp = ALIGN_DOWN(ukarch_regs_get_sp(&execenv->regs),
+                                 UKARCH_SP_ALIGN);
+               uk_pr_debug("Using the application stack @ 0x%lx\n", ulsp);
+       }
+
+       /* Signal handlers can make syscalls, that can invoke signal handlers,
+        * that can make syscalls, and so on. We need to support nesting.
+        * Since on syscall entry we switch to the auxsp, nested syscalls will
+        * corrupt the previous syscall's stack. To avoid that from happening,
+        * save the base auxsp of this syscall. Once the handler returns we will
+        * restore the original value. Moreover, prepare a new base auxsp for
+        * the nested syscall based on the current (aligned) value of the auxsp.
+        */
+
+       /* Assuming that we are operating on the auxsp and that
+        * the sp has moved down since entry, align down to
+        * UKARCH_AUXSP_ALIGN so that a nested syscall finds the
+        * auxsp aligned. Make sure we reserve enough space for
+        * pprocess_signal_arch_jmp_handler() to save our general
+        * purpose registers before we jump to the application
+        * handler.
+        */
+       auxspcb = ukarch_auxsp_get_cb(uk_thread_current()->auxsp);
+       saved_fp = ukarch_auxspcb_get_curr_fp(auxspcb);
+
+       fp = ALIGN_DOWN(ukarch_read_sp(), UKARCH_AUXSP_ALIGN);
+       ukarch_auxspcb_set_curr_fp(auxspcb, fp);
+
+       if (ks->ks_flags & SA_SIGINFO) {
+               pprocess_signal_arch_set_ucontext(execenv, &ucontext);
+               jmp_handler(execenv, sig->siginfo.si_signo,
+                           &sig->siginfo, &ucontext,
+                           ks->ks_handler, (void *)ulsp);
+               pprocess_signal_arch_get_ucontext(&ucontext, execenv);
+       } else {
+               jmp_handler(execenv, sig->siginfo.si_signo,
+                           NULL, NULL, ks->ks_handler,
+                           (void *)ulsp);
+       }
+
+       /* Restore the aux stack's fp */
+       ukarch_auxspcb_set_curr_fp(auxspcb, saved_fp);
+
+       if (ks->ks_flags & SA_ONSTACK) {
+               UK_ASSERT(altstack->ss_flags & SS_ONSTACK);
+               UK_ASSERT(!(altstack->ss_flags & SS_DISABLE));
+               altstack->ss_flags &= ~SS_ONSTACK;
+       }
+}
+
+/* Deliver a signal to a thread. The caller must check that the signal
+ * is not masked by the handling thread or ignored by the process or its
+ * default disposition.
+ */
+static int do_deliver(struct posix_thread *pthread, struct uk_signal *sig,
+                     struct ukarch_execenv *execenv)
+{
+       struct posix_process *pproc;
+       uk_sigset_t saved_mask;
+       int signum;
+
+       UK_ASSERT(sig && sig->siginfo.si_signo);
+       UK_ASSERT(pthread);
+
+       pproc = tid2pprocess(pthread->tid);
+       UK_ASSERT(pproc);
+
+       signum = sig->siginfo.si_signo;
+
+       /* Execute the default action if a signal handler is not defined */
+       if (KERN_SIGACTION(pproc, signum)->ks_handler == SIG_DFL) {
+               /* Standard signals: Invoke signal-specific default action */
+               if (signum < SIGRTMIN) {
+                       if (UK_BIT(signum) & SIGACT_CORE_MASK)
+                               uk_sigact_core(signum);
+                       else if (UK_BIT(signum) & SIGACT_TERM_MASK)
+                               uk_sigact_term(signum);
+                       else if (UK_BIT(signum) & SIGACT_STOP_MASK)
+                               uk_sigact_stop(signum);
+                       else if (UK_BIT(signum) & SIGACT_CONT_MASK)
+                               uk_sigact_cont(signum);
+                       else if (UK_BIT(signum) & SIGACT_IGN_MASK)
+                               uk_sigact_ign(signum);
+                       else
+                               UK_BUG();
+               } else {
+                       /* Real-time signals: SIG_TERM by default */
+                       uk_sigact_term(signum);
+               }
+               return 0;
+       }
+
+       /* Save original mask and apply mask from sigaction */
+       saved_mask = pthread->signal->mask;
+       uk_sigorset(&pthread->signal->mask,
+                   &KERN_SIGACTION(pproc, signum)->ks_mask);
+
+       /* Also add this signal to masked signals */
+       if (!(KERN_SIGACTION(pproc, signum)->ks_flags & SA_NODEFER))
+               SET_MASKED(pthread, signum);
+
+       /* Execute handler */
+       handle_self(sig, KERN_SIGACTION(pproc, signum), execenv);
+
+       /* Restore original mask */
+       pthread->signal->mask = saved_mask;
+
+       /* If SA_RESETHAND flag is set, restore the default handler */
+       if (KERN_SIGACTION(pproc, signum)->ks_flags & SA_RESETHAND)
+               pprocess_signal_sigaction_clear(KERN_SIGACTION(pproc, signum));
+
+       return 0;
+}
+
+/* Deliver pending signals of a given process. We deliver each
+ * pending signal to the first thread that doesn't mask that
+ * signal.
+ */
+static int deliver_pending_proc(struct posix_process *proc,
+                               struct ukarch_execenv *execenv)
+{
+       struct posix_thread *thread, *threadn;
+       struct posix_thread *this_thread;
+       struct uk_signal *sig;
+       int handled_cnt = 0;
+       bool handled;
+       int signum;
+
+       UK_ASSERT(proc);
+       UK_ASSERT(execenv);
+
+       this_thread = uk_pthread_current();
+       UK_ASSERT(this_thread);
+
+       pprocess_signal_foreach(signum) {
+               handled = false;
+
+               /* Skip if the process ignores this signal altogether */
+               if (IS_IGNORED(proc, signum))
+                       continue;
+
+               /* POSIX specifies that if a signal targets the
+                * current process / thread, then at least one
+                * signal for this process /thread must be
+                * delivered before the syscall returns, as long as:
+                *
+                * 1. No other thread has that signal unblocked
+                * 2. No other thread is in sigwait() for that signal (TODO)
+                */
+               uk_pprocess_foreach_pthread(proc, thread, threadn) {
+                       if (thread->tid == this_thread->tid)
+                               continue;
+
+                       if (IS_MASKED(thread, signum))
+                               continue;
+
+                       while ((sig = pprocess_signal_dequeue(proc, NULL,
+                                                             signum))) {
+                               do_deliver(thread, sig, execenv);
+                               uk_signal_free(proc->_a, sig);
+                               handled = true;
+                               handled_cnt++;
+                       }
+                       break;
+               }
+
+               /* Try to deliver to this thread */
+               if (!handled) {
+                       if (IS_MASKED(this_thread, signum))
+                               continue;
+
+                       while ((sig = pprocess_signal_dequeue(proc, NULL,
+                                                             signum))) {
+                               do_deliver(this_thread, sig, execenv);
+                               uk_signal_free(proc->_a, sig);
+                               handled = true;
+                               handled_cnt++;
+                       }
+               }
+       }
+
+       return handled_cnt;
+}
+
+static int deliver_pending_thread(struct posix_thread *thread,
+                                 struct ukarch_execenv *execenv)
+{
+       struct posix_process *proc;
+       struct uk_signal *sig;
+       int handled = 0;
+       int signum;
+
+       proc = tid2pprocess(thread->tid);
+       UK_ASSERT(proc);
+
+       /* Deliver this thread's signals. SUS requires that RT signals
+        * must be delivered starting from the lowest signal number.
+        * Delivery order of standard signals is undefined. We deliver
+        * all signals in order.
+        */
+       pprocess_signal_foreach(signum) {
+               if (!pprocess_signal_is_deliverable(thread, signum))
+                       continue;
+
+               while ((sig = pprocess_signal_dequeue(proc, thread, signum))) {
+                       do_deliver(thread, sig, execenv);
+                       uk_signal_free(thread->_a, sig);
+                       handled++;
+               }
+       }
+
+       return handled;
+}
+
+static void uk_signal_deliver(struct uk_syscall_exit_ctx *exit_ctx)
+{
+       struct ukarch_execenv *execenv;
+       struct posix_thread *pthread;
+       struct posix_process *pproc;
+
+       UK_ASSERT(exit_ctx);
+
+       execenv = exit_ctx->execenv;
+
+       /* FIXME: This can go away once we eliminate the last syscall made
+        *        by kernel context and pass execenv to syscalls in native
+        *        mode.
+        */
+       if (!execenv)
+               return;
+
+       pthread = uk_pthread_current();
+       UK_ASSERT(pthread);
+
+       pproc = uk_pprocess_current();
+       UK_ASSERT(pproc);
+
+       /* If there's SIGKILL pending, kill the process right away */
+       if (IS_PENDING(pproc->signal->sigqueue, SIGKILL)) {
+               uk_pr_info("SIGKILL tid %d\n", uk_sys_gettid());
+               uk_sigact_term(SIGKILL);
+               /* We assume that we always call this function
+                * on the running process.
+                */
+               UK_BUG();
+       }
+
+       /* SIGSTOP / SIGCONT should have been already ignored by rt_sigaction */
+       UK_ASSERT(!IS_PENDING(pproc->signal->sigqueue, SIGSTOP));
+       UK_ASSERT(!IS_PENDING(pproc->signal->sigqueue, SIGCONT));
+
+       /* Deliver all pending signals of this process & thread */
+       deliver_pending_proc(pproc, execenv);
+       if (pthread->state == POSIX_THREAD_RUNNING ||
+           pthread->state == POSIX_THREAD_BLOCKED_SIGNAL)
+               deliver_pending_thread(pthread, execenv);
+}
+
+uk_syscall_exittab_prio(uk_signal_deliver, UK_PRIO_BEFORE(UK_PRIO_LATEST));
index fbb7a3d78b1419c187cc816660cdde47fddc6c15..c8dbb03bf8ed02e68aefd7ef6da7a401de0a2e8e 100644 (file)
@@ -261,6 +261,40 @@ int pprocess_signal_thread_do(int tid, int signum, siginfo_t *siginfo);
 /* Signal a process */
 int pprocess_signal_send(struct posix_process *proc, int signum,
                         siginfo_t *siginfo);
+
+/* Jump to signal handler
+ *
+ * Trampoline to jump from unikraft to userspace context.
+ *
+ * @param signum signal number
+ * @param si     data to pass as the 2nd parameter to the handler
+ *               if SA_SIGINFO is set, or NULL
+ * @param ctx    user context to pass as the 3rd parameter to
+ *               the handler if SA_SIGINFO is set, or NULL
+ * @param sp     the user stack pointer address to switch to
+ *               before calling the handler
+ */
+void pprocess_signal_arch_jmp_handler(struct ukarch_execenv *execenv,
+                                     int signum, siginfo_t *si,
+                                     ucontext_t *ctx,
+                                     void *handler, void *sp);
+
+/* Populate POSIX u_context from ukarch_execenv */
+void pprocess_signal_arch_set_ucontext(struct ukarch_execenv *execenv,
+                                      ucontext_t *ucontext);
+
+/* Populate ukarch_execenv from POSIX u_context */
+void pprocess_signal_arch_get_ucontext(ucontext_t *ucontext,
+                                      struct ukarch_execenv *execenv);
+
+/* Checks whether a signal can be delivered to a given thread, depending
+ * on the thread's mask, whether the process chooses to ingores this signal,
+ * or whether the process uses a default disposition of ignore.
+ *
+ * Does NOT check permissions.
+ */
+bool pprocess_signal_is_deliverable(struct posix_thread *pthread, int signum);
+
 #endif /* CONFIG_LIBPOSIX_PROCESS_PIDS */
 
 #endif /* __UK_PROCESS_SIGNAL_H__ */