From 0c5df0036c5d8975d4c986f624a4de5d3042c79f Mon Sep 17 00:00:00 2001 From: Alexander Boettcher Date: Thu, 18 Jul 2024 17:11:41 +0200 Subject: [PATCH] libc: support to execute signal on separate stack With the commit LibC signals will be executed on a separate stack and not anymore on the kernel or user stack. Fixes #5305 --- repos/libports/src/lib/libc/internal/signal.h | 50 ++++++++++++++++++- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/repos/libports/src/lib/libc/internal/signal.h b/repos/libports/src/lib/libc/internal/signal.h index 691e86b18e..d3cd395f65 100644 --- a/repos/libports/src/lib/libc/internal/signal.h +++ b/repos/libports/src/lib/libc/internal/signal.h @@ -22,6 +22,7 @@ #include /* libc-internal includes */ +#include #include namespace Libc { struct Signal; } @@ -60,6 +61,52 @@ struct Libc::Signal : Noncopyable pid_t const _local_pid; + void * _signal_stack { }; + jmp_buf _signal_context { }; + + struct Signal_arguments + { + Signal & signal; + Pending & pending; + + Signal_arguments(Signal &signal, Pending &pending) + : signal(signal), pending(pending) { } + }; + + static void _signal_entry(Signal_arguments &arg) + { + arg.signal._execute_signal_handler(arg.pending.n); + arg.signal._charged_signals[arg.pending.n].destruct(); + + _longjmp(arg.signal._signal_context, 1); + } + + void _execute_on_signal_stack(Pending &pending) + { + if (!_signal_stack) { + auto myself = Thread::myself(); + if (myself) + _signal_stack = { myself->alloc_secondary_stack("signal", 16 * 1024) }; + } + + if (!_signal_stack) { + error("signal stack allocation failed"); + return; + } + + /* save continuation of current stack */ + if (!_setjmp(_signal_context)) { + + Signal_arguments arg(*this, pending); + + /* _setjmp() returned directly -> switch to signal stack */ + call_func(_signal_stack, (void *)_signal_entry, (void *)&arg); + + /* never reached */ + } + /* _setjmp() returned after _longjmp() */ + } + public: Signal(pid_t local_pid) : _local_pid(local_pid) { } @@ -87,8 +134,7 @@ struct Libc::Signal : Noncopyable _nesting_level++; _pending_signals.for_each([&] (Pending &pending) { - _execute_signal_handler(pending.n); - _charged_signals[pending.n].destruct(); + _execute_on_signal_stack(pending); }); _nesting_level--;