* [RFC PATCH 0/6] Xenomai: Real-time Exception Handling
@ 2025-04-08 12:28 Nikolaus Funk
2025-04-08 12:28 ` [PATCH 1/6] cobalt/x86: Add architecture specific signal code Nikolaus Funk
` (6 more replies)
0 siblings, 7 replies; 10+ messages in thread
From: Nikolaus Funk @ 2025-04-08 12:28 UTC (permalink / raw)
To: xenomai; +Cc: richard, Richard Weinberger
From: Richard Weinberger <richard@nod.at>
Currently, any exception that occurs in primary mode triggers a switch
to secondary mode, and Linux posts a signal.
This change allows certain exceptions to be handled directly in the
affected thread while remaining in primary mode.
At present, only SIGILL (for x86, arm32 and arm64) and SIGFPE (for x86)
are supported.
Adding support for additional exceptions is possible but requires
careful consideration, as not all exception types can be analyzed in
real-time. A notable example is a page fault, determining whether
SIGSEGV is appropriate requires deep traversal into the memory
management code.
Patches 1, 2, 3, and 4 implement the Xenomai-side changes for this
feature. Dovetail will receive a separate patch set. Patches 5 and 6
introduce tests.
It is important to note that this is not a fully-fledged signal
implementation. The only supported use case is delivering exceptions
as signals to the affected thread.
There is no support for sending signals or handling block/ignore masks.
The only user visible API so far is cobalt_rt_signal().
It takes a signal number (SIGILL or SIGFPE so far) and a handler
function with the signature fn(int, siginfo_t *, void *).
TODO:
- Better naming, IMHO "signal" is the wrong term and will confuse users.
Especially since POSIX real-time signals are something different.
Maybe "umex" for "user mode exception handling"?
- Document new APIs
- Improve tests
- Carefully select more exceptions
Lorenz Kofler (5):
cobalt/x86: Add architecture specific signal code
cobalt/arm64: Add architecture specific signal code
cobalt: Add signal core code
testsuite: smokey: Add testcases for signals
utils: Add rt_signal_hist
Richard Weinberger (1):
cobalt/arm: Add architecture specific signal code
configure.ac | 3 +
include/cobalt/kernel/ppd.h | 3 +
include/cobalt/kernel/thread.h | 8 +
include/cobalt/signal.h | 2 +
include/cobalt/uapi/syscall.h | 2 +
kernel/cobalt/arch/arm/Makefile | 2 +-
kernel/cobalt/arch/arm/signal.c | 27 ++
kernel/cobalt/arch/arm64/Makefile | 2 +-
kernel/cobalt/arch/arm64/signal.c | 28 ++
kernel/cobalt/arch/x86/Makefile | 2 +-
kernel/cobalt/arch/x86/signal.c | 51 +++
kernel/cobalt/dovetail/kevents.c | 5 +
.../include/asm-generic/xenomai/thread.h | 3 +
kernel/cobalt/posix/syscall.c | 41 ++
kernel/cobalt/thread.c | 59 +++
kernel/cobalt/trace/cobalt-posix.h | 4 +-
.../arch/arm/include/asm/xenomai/syscall.h | 9 +
.../arch/arm64/include/asm/xenomai/syscall.h | 9 +
.../arch/x86/include/asm/xenomai/syscall.h | 15 +
lib/cobalt/signal.c | 19 +
testsuite/smokey/Makefile.am | 2 +
testsuite/smokey/rtsignals/Makefile.am | 57 +++
testsuite/smokey/rtsignals/rtsignals.c | 35 ++
testsuite/smokey/rtsignals/rtsignals_test.c | 370 ++++++++++++++++++
utils/Makefile.am | 2 +-
utils/rt_signal_hist/Makefile.am | 22 ++
utils/rt_signal_hist/error.h | 15 +
utils/rt_signal_hist/histo.c | 47 +++
utils/rt_signal_hist/histo.h | 14 +
utils/rt_signal_hist/result.c | 17 +
utils/rt_signal_hist/result.h | 13 +
utils/rt_signal_hist/rt_signal_hist.c | 237 +++++++++++
32 files changed, 1120 insertions(+), 5 deletions(-)
create mode 100644 kernel/cobalt/arch/arm/signal.c
create mode 100644 kernel/cobalt/arch/arm64/signal.c
create mode 100644 kernel/cobalt/arch/x86/signal.c
create mode 100644 testsuite/smokey/rtsignals/Makefile.am
create mode 100644 testsuite/smokey/rtsignals/rtsignals.c
create mode 100644 testsuite/smokey/rtsignals/rtsignals_test.c
create mode 100644 utils/rt_signal_hist/Makefile.am
create mode 100644 utils/rt_signal_hist/error.h
create mode 100644 utils/rt_signal_hist/histo.c
create mode 100644 utils/rt_signal_hist/histo.h
create mode 100644 utils/rt_signal_hist/result.c
create mode 100644 utils/rt_signal_hist/result.h
create mode 100644 utils/rt_signal_hist/rt_signal_hist.c
--
2.48.1
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 1/6] cobalt/x86: Add architecture specific signal code
2025-04-08 12:28 [RFC PATCH 0/6] Xenomai: Real-time Exception Handling Nikolaus Funk
@ 2025-04-08 12:28 ` Nikolaus Funk
2025-04-08 12:28 ` [PATCH 2/6] cobalt/arm64: " Nikolaus Funk
` (5 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Nikolaus Funk @ 2025-04-08 12:28 UTC (permalink / raw)
To: xenomai; +Cc: richard, Lorenz Kofler, Johannes Kirchmair
From: Lorenz Kofler <lorenz@sigma-star.at>
On x86 SIGFPE and SIGILL are supported.
They are generated from #DE, #MF and #UD exceptions.
si_errno, si_code and si_addr are modelled to match what
Linux does.
Co-developed-by: Johannes Kirchmair <johannes.kirchmair@sigmatek.at>
Co-developed-by: Richard Weinberger <richard@sigma-star.at>
Signed-off-by: Lorenz Kofler <lorenz@sigma-star.at>
---
kernel/cobalt/arch/x86/Makefile | 2 +-
kernel/cobalt/arch/x86/signal.c | 51 +++++++++++++++++++
.../arch/x86/include/asm/xenomai/syscall.h | 15 ++++++
3 files changed, 67 insertions(+), 1 deletion(-)
create mode 100644 kernel/cobalt/arch/x86/signal.c
diff --git a/kernel/cobalt/arch/x86/Makefile b/kernel/cobalt/arch/x86/Makefile
index 93929b645..e3d8eb476 100644
--- a/kernel/cobalt/arch/x86/Makefile
+++ b/kernel/cobalt/arch/x86/Makefile
@@ -1,5 +1,5 @@
obj-$(CONFIG_XENOMAI) += xenomai.o
-xenomai-y := machine.o smi.o c1e.o
+xenomai-y := machine.o smi.o c1e.o signal.o
ccflags-y := -I$(srctree)/arch/x86/xenomai/include -I$(srctree)/include/xenomai
diff --git a/kernel/cobalt/arch/x86/signal.c b/kernel/cobalt/arch/x86/signal.c
new file mode 100644
index 000000000..6da31aa4c
--- /dev/null
+++ b/kernel/cobalt/arch/x86/signal.c
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/signal.h>
+#include <linux/uaccess.h>
+#include <cobalt/kernel/thread.h>
+
+#include <asm/sigframe.h>
+#include <asm/sighandling.h>
+#include <asm/fpu/signal.h>
+#include <asm/trapnr.h>
+
+int xnarch_setup_trap_info(unsigned int vector, struct pt_regs *regs,
+ int *sig, struct kernel_siginfo *info)
+{
+ switch (vector) {
+ case X86_TRAP_DE: /* divide_error */
+ *sig = SIGFPE;
+ info->si_errno = 0;
+ info->si_code = FPE_INTDIV;
+ info->si_addr = (void __user *)xnarch_fault_pc(regs);
+ break;
+ case X86_TRAP_MF:
+ *sig = SIGFPE;
+ info->si_errno = 0;
+ info->si_code = 0;
+ info->si_addr = (void __user *)xnarch_fault_pc(regs);
+ break;
+ case X86_TRAP_UD: /* invalid_op */
+ *sig = SIGILL;
+ info->si_errno = 0;
+ info->si_code = ILL_ILLOPN;
+ info->si_addr = (void __user *)xnarch_fault_pc(regs);
+ break;
+ default:
+ return -ENOSYS;
+ }
+
+ info->si_signo = *sig;
+
+ return 0;
+}
+
+void xnarch_fixup_trap_regs(struct pt_regs *regs)
+{
+ regs->flags &= ~(X86_EFLAGS_DF|X86_EFLAGS_RF|X86_EFLAGS_TF);
+}
+
+bool xnarch_is_supported_signal(int sig)
+{
+ return sig == SIGILL || sig == SIGFPE;
+}
diff --git a/lib/cobalt/arch/x86/include/asm/xenomai/syscall.h b/lib/cobalt/arch/x86/include/asm/xenomai/syscall.h
index 79bf17ee7..f317419b3 100644
--- a/lib/cobalt/arch/x86/include/asm/xenomai/syscall.h
+++ b/lib/cobalt/arch/x86/include/asm/xenomai/syscall.h
@@ -20,6 +20,7 @@
#include <xeno_config.h>
#include <cobalt/uapi/syscall.h>
+#include <boilerplate/compiler.h>
/* Some code pulled from glibc's inline syscalls. */
@@ -135,6 +136,13 @@ asm (".L__X'%ebx = 1\n\t"
#define XENOMAI_SYSBIND(breq) \
XENOMAI_DO_SYSCALL_SAFE(1, sc_cobalt_bind, breq)
+#define XENOMAI_BUILD_SIGRETURN() \
+ __asm__ ( \
+ ".text\n\t" \
+ "__cobalt_sigreturn:\n\t" \
+ "movl $" __stringify(__xn_syscode(sc_cobalt_sigreturn)) ",%eax\n\t" \
+ DOSYSCALLSAFE);
+
#else /* x86_64 */
#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 3)
@@ -204,6 +212,13 @@ asm (".L__X'%ebx = 1\n\t"
#define XENOMAI_SYSBIND(breq) \
XENOMAI_DO_SYSCALL(1, sc_cobalt_bind, breq)
+#define XENOMAI_BUILD_SIGRETURN() \
+ __asm__ ( \
+ ".text\n\t" \
+ "__cobalt_sigreturn:\n\t" \
+ "movq $" __stringify(__xn_syscode(sc_cobalt_sigreturn)) ",%rax\n\t" \
+ "syscall\n\t");
+
#endif /* x86_64 */
#define XENOMAI_SYSCALL0(op) XENOMAI_DO_SYSCALL(0,op)
--
2.48.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 2/6] cobalt/arm64: Add architecture specific signal code
2025-04-08 12:28 [RFC PATCH 0/6] Xenomai: Real-time Exception Handling Nikolaus Funk
2025-04-08 12:28 ` [PATCH 1/6] cobalt/x86: Add architecture specific signal code Nikolaus Funk
@ 2025-04-08 12:28 ` Nikolaus Funk
2025-04-08 12:28 ` [PATCH 3/6] cobalt/arm: " Nikolaus Funk
` (4 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Nikolaus Funk @ 2025-04-08 12:28 UTC (permalink / raw)
To: xenomai; +Cc: richard, Lorenz Kofler, Johannes Kirchmair
From: Lorenz Kofler <lorenz@sigma-star.at>
Add code for the ARM64 side including ARM32 compat mode.
The only supported signal so far is SIGILL, it is built from
BTI and UNDI exceptions.
Co-developed-by: Johannes Kirchmair <johannes.kirchmair@sigmatek.at>
Co-developed-by: Richard Weinberger <richard@sigma-star.at>
Signed-off-by: Lorenz Kofler <lorenz@sigma-star.at>
---
kernel/cobalt/arch/arm64/Makefile | 2 +-
kernel/cobalt/arch/arm64/signal.c | 28 +++++++++++++++++++
.../arch/arm/include/asm/xenomai/syscall.h | 9 ++++++
.../arch/arm64/include/asm/xenomai/syscall.h | 9 ++++++
4 files changed, 47 insertions(+), 1 deletion(-)
create mode 100644 kernel/cobalt/arch/arm64/signal.c
diff --git a/kernel/cobalt/arch/arm64/Makefile b/kernel/cobalt/arch/arm64/Makefile
index 6c872fdb2..125b4cc56 100644
--- a/kernel/cobalt/arch/arm64/Makefile
+++ b/kernel/cobalt/arch/arm64/Makefile
@@ -1,5 +1,5 @@
obj-$(CONFIG_XENOMAI) += xenomai.o
-xenomai-y := machine.o
+xenomai-y := machine.o signal.o
ccflags-y := -I$(srctree)/arch/arm64/xenomai/include -I$(srctree)/include/xenomai
diff --git a/kernel/cobalt/arch/arm64/signal.c b/kernel/cobalt/arch/arm64/signal.c
new file mode 100644
index 000000000..2e586aaa6
--- /dev/null
+++ b/kernel/cobalt/arch/arm64/signal.c
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <cobalt/kernel/thread.h>
+
+int xnarch_setup_trap_info(unsigned int vector, struct pt_regs *regs,
+ int *sig, struct kernel_siginfo *info)
+{
+ switch (vector) {
+ case ARM64_TRAP_UNDI:
+ case ARM64_TRAP_BTI:
+ *sig = SIGILL;
+ info->si_errno = 0;
+ info->si_code = ILL_ILLOPC;
+ info->si_addr = (void __user *)xnarch_fault_pc(regs);
+ break;
+ default:
+ return -ENOSYS;
+ }
+
+ info->si_signo = *sig;
+
+ return 0;
+}
+
+bool xnarch_is_supported_signal(int sig)
+{
+ return sig == SIGILL;
+}
diff --git a/lib/cobalt/arch/arm/include/asm/xenomai/syscall.h b/lib/cobalt/arch/arm/include/asm/xenomai/syscall.h
index 105bf9faf..da1cf4a21 100644
--- a/lib/cobalt/arch/arm/include/asm/xenomai/syscall.h
+++ b/lib/cobalt/arch/arm/include/asm/xenomai/syscall.h
@@ -24,6 +24,7 @@
#include <xeno_config.h>
#include <errno.h>
#include <cobalt/uapi/syscall.h>
+#include <boilerplate/compiler.h>
#ifndef __ARM_EABI__
#error "ARM OABI support has been removed with Xenomai 3.3.x"
@@ -119,4 +120,12 @@
#define XENOMAI_SYSBIND(breq) \
XENOMAI_DO_SYSCALL(1,sc_cobalt_bind,breq)
+#define XENOMAI_BUILD_SIGRETURN() \
+ __asm__ ( \
+ ".text\n\t" \
+ "__cobalt_sigreturn:\n\t" \
+ "mov %r7,$" __stringify(sc_cobalt_sigreturn) "\n\t" \
+ "orr %r7,%r7,$" __stringify(__COBALT_SYSCALL_BIT) "\n\t"\
+ "swi 0\n\t");
+
#endif /* !_LIB_COBALT_ARM_SYSCALL_H */
diff --git a/lib/cobalt/arch/arm64/include/asm/xenomai/syscall.h b/lib/cobalt/arch/arm64/include/asm/xenomai/syscall.h
index d89697712..bbfb9c172 100644
--- a/lib/cobalt/arch/arm64/include/asm/xenomai/syscall.h
+++ b/lib/cobalt/arch/arm64/include/asm/xenomai/syscall.h
@@ -22,6 +22,7 @@
#include <xeno_config.h>
#include <errno.h>
#include <cobalt/uapi/syscall.h>
+#include <boilerplate/compiler.h>
#define __xn_syscall_args0
#define __xn_syscall_args1 , unsigned long __a1
@@ -101,4 +102,12 @@ DEFINE_XENOMAI_SYSCALL(5)
__xenomai_do_syscall1(sc_cobalt_bind, \
(unsigned long)__breq)
+#define XENOMAI_BUILD_SIGRETURN() \
+ __asm__ ( \
+ ".text\n\t" \
+ "__cobalt_sigreturn:\n\t" \
+ "mov w8,#" __stringify(sc_cobalt_sigreturn) "\n\t" \
+ "orr w8,w8,#" __stringify(__COBALT_SYSCALL_BIT) "\n\t" \
+ "svc 0\n\t");
+
#endif /* !_LIB_COBALT_ARM64_SYSCALL_H */
--
2.48.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 3/6] cobalt/arm: Add architecture specific signal code
2025-04-08 12:28 [RFC PATCH 0/6] Xenomai: Real-time Exception Handling Nikolaus Funk
2025-04-08 12:28 ` [PATCH 1/6] cobalt/x86: Add architecture specific signal code Nikolaus Funk
2025-04-08 12:28 ` [PATCH 2/6] cobalt/arm64: " Nikolaus Funk
@ 2025-04-08 12:28 ` Nikolaus Funk
2025-04-08 12:28 ` [PATCH 4/6] cobalt: Add signal core code Nikolaus Funk
` (3 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Nikolaus Funk @ 2025-04-08 12:28 UTC (permalink / raw)
To: xenomai; +Cc: richard, Richard Weinberger
From: Richard Weinberger <richard@nod.at>
Add code for the ARM32 side.
The only supported signal so far is SIGILL, it is built from
the UND exception.
Signed-off-by: Richard Weinberger <richard@nod.at>
---
kernel/cobalt/arch/arm/Makefile | 2 +-
kernel/cobalt/arch/arm/signal.c | 27 +++++++++++++++++++++++++++
2 files changed, 28 insertions(+), 1 deletion(-)
create mode 100644 kernel/cobalt/arch/arm/signal.c
diff --git a/kernel/cobalt/arch/arm/Makefile b/kernel/cobalt/arch/arm/Makefile
index 13cbf84a9..d06d3d425 100644
--- a/kernel/cobalt/arch/arm/Makefile
+++ b/kernel/cobalt/arch/arm/Makefile
@@ -1,5 +1,5 @@
obj-$(CONFIG_XENOMAI) += xenomai.o
-xenomai-y := machine.o
+xenomai-y := machine.o signal.o
ccflags-y := -I$(srctree)/arch/arm/xenomai/include -I$(srctree)/include/xenomai
diff --git a/kernel/cobalt/arch/arm/signal.c b/kernel/cobalt/arch/arm/signal.c
new file mode 100644
index 000000000..703230229
--- /dev/null
+++ b/kernel/cobalt/arch/arm/signal.c
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <cobalt/kernel/thread.h>
+
+int xnarch_setup_trap_info(unsigned int vector, struct pt_regs *regs,
+ int *sig, struct kernel_siginfo *info)
+{
+ switch (vector) {
+ case ARM_TRAP_UNDEFINSTR:
+ *sig = SIGILL;
+ info->si_errno = 0;
+ info->si_code = ILL_ILLOPC;
+ info->si_addr = (void __user *)xnarch_fault_pc(regs);
+ break;
+ default:
+ return -ENOSYS;
+ }
+
+ info->si_signo = *sig;
+
+ return 0;
+}
+
+bool xnarch_is_supported_signal(int sig)
+{
+ return sig == SIGILL;
+}
--
2.48.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 4/6] cobalt: Add signal core code
2025-04-08 12:28 [RFC PATCH 0/6] Xenomai: Real-time Exception Handling Nikolaus Funk
` (2 preceding siblings ...)
2025-04-08 12:28 ` [PATCH 3/6] cobalt/arm: " Nikolaus Funk
@ 2025-04-08 12:28 ` Nikolaus Funk
2025-04-08 12:28 ` [PATCH 5/6] testsuite: smokey: Add testcases for signals Nikolaus Funk
` (2 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Nikolaus Funk @ 2025-04-08 12:28 UTC (permalink / raw)
To: xenomai; +Cc: richard, Lorenz Kofler, Johannes Kirchmair
From: Lorenz Kofler <lorenz@sigma-star.at>
Currently, any exception that occurs in primary mode triggers a switch
to secondary mode, and Linux posts a signal.
This change enables certain exceptions to be handled directly in the
affected thread while remaining in primary mode.
The approach is loosely inspired by Linux's signal handling but is
implemented in a simpler manner.
For example, nesting identical signals is not supported. Additionally,
while a signal is being handled, it is added to the thread's blocking
set.
Co-developed-by: Johannes Kirchmair <johannes.kirchmair@sigmatek.at>
Co-developed-by: Richard Weinberger <richard@sigma-star.at>
Signed-off-by: Lorenz Kofler <lorenz@sigma-star.at>
---
include/cobalt/kernel/ppd.h | 3 +
include/cobalt/kernel/thread.h | 8 +++
include/cobalt/signal.h | 2 +
include/cobalt/uapi/syscall.h | 2 +
kernel/cobalt/dovetail/kevents.c | 5 ++
.../include/asm-generic/xenomai/thread.h | 3 +
kernel/cobalt/posix/syscall.c | 41 +++++++++++++
kernel/cobalt/thread.c | 59 +++++++++++++++++++
kernel/cobalt/trace/cobalt-posix.h | 4 +-
lib/cobalt/signal.c | 19 ++++++
10 files changed, 145 insertions(+), 1 deletion(-)
diff --git a/include/cobalt/kernel/ppd.h b/include/cobalt/kernel/ppd.h
index f0079fe6e..fb2f682da 100644
--- a/include/cobalt/kernel/ppd.h
+++ b/include/cobalt/kernel/ppd.h
@@ -22,6 +22,7 @@
#include <linux/types.h>
#include <linux/atomic.h>
#include <linux/rbtree.h>
+#include <linux/signal.h>
#include <cobalt/kernel/heap.h>
struct cobalt_umm {
@@ -32,6 +33,8 @@ struct cobalt_umm {
struct cobalt_ppd {
struct cobalt_umm umm;
+ void __user *sighand[_NSIG];
+ void __user *sigrestorer;
atomic_t refcnt;
char *exe_path;
struct rb_root fds;
diff --git a/include/cobalt/kernel/thread.h b/include/cobalt/kernel/thread.h
index 04fad0e49..6c6609ef4 100644
--- a/include/cobalt/kernel/thread.h
+++ b/include/cobalt/kernel/thread.h
@@ -220,6 +220,8 @@ struct xnthread {
#endif
struct lostage_signal sigarray[XNTHREAD_MAX_SIGNALS];
struct lostage_wakeup relax_work;
+
+ sigset_t sigblocked;
};
static inline int xnthread_get_state(const struct xnthread *thread)
@@ -581,6 +583,12 @@ static inline void xnthread_propagate_schedparam(struct xnthread *curr)
extern struct xnthread_personality xenomai_personality;
+bool xnthread_handle_rt_signals(unsigned int trapnr, struct pt_regs *regs);
+
+void xnarch_fixup_trap_regs(struct pt_regs *regs);
+
+bool xnarch_is_supported_signal(int sig);
+
/** @} */
#endif /* !_COBALT_KERNEL_THREAD_H */
diff --git a/include/cobalt/signal.h b/include/cobalt/signal.h
index 55cb2baba..cd37652c4 100644
--- a/include/cobalt/signal.h
+++ b/include/cobalt/signal.h
@@ -54,6 +54,8 @@ COBALT_DECL(int, kill, (pid_t pid, int sig));
COBALT_DECL(int, sigqueue, (pid_t pid, int sig, const union sigval value));
+int cobalt_rt_signal(int sig, void (*handler)(int, siginfo_t *, void *));
+
#ifdef __cplusplus
}
#endif
diff --git a/include/cobalt/uapi/syscall.h b/include/cobalt/uapi/syscall.h
index f27988f55..0f43c5488 100644
--- a/include/cobalt/uapi/syscall.h
+++ b/include/cobalt/uapi/syscall.h
@@ -141,6 +141,8 @@
#define sc_cobalt_timerfd_settime64 118
#define sc_cobalt_timerfd_gettime64 119
#define sc_cobalt_pselect64 120
+#define sc_cobalt_sigreturn 121
+#define sc_cobalt_sigaction 122
#define __NR_COBALT_SYSCALLS 128 /* Power of 2 */
diff --git a/kernel/cobalt/dovetail/kevents.c b/kernel/cobalt/dovetail/kevents.c
index 0f70dbc27..d962d5418 100644
--- a/kernel/cobalt/dovetail/kevents.c
+++ b/kernel/cobalt/dovetail/kevents.c
@@ -56,6 +56,11 @@ void handle_oob_trap_entry(unsigned int trapnr, struct pt_regs *regs)
xnsched_run();
}
+ if (xnthread_test_state(thread, XNUSER) &&
+ user_mode(regs) &&
+ xnthread_handle_rt_signals(trapnr, regs))
+ return;
+
/*
* If we experienced a trap on behalf of a shadow thread
* running in primary mode, move it to the Linux domain,
diff --git a/kernel/cobalt/include/asm-generic/xenomai/thread.h b/kernel/cobalt/include/asm-generic/xenomai/thread.h
index 3881917bd..e886a706a 100644
--- a/kernel/cobalt/include/asm-generic/xenomai/thread.h
+++ b/kernel/cobalt/include/asm-generic/xenomai/thread.h
@@ -21,4 +21,7 @@ struct task_struct *xnarch_host_task(struct xnarchtcb *tcb)
return tcb->altsched.task;
}
+int xnarch_setup_trap_info(unsigned int vector, struct pt_regs *regs,
+ int *sig, struct kernel_siginfo *info);
+
#endif /* !_COBALT_ASM_GENERIC_THREAD_H */
diff --git a/kernel/cobalt/posix/syscall.c b/kernel/cobalt/posix/syscall.c
index a26da154c..2a8c1e56b 100644
--- a/kernel/cobalt/posix/syscall.c
+++ b/kernel/cobalt/posix/syscall.c
@@ -19,6 +19,7 @@
#include <linux/types.h>
#include <linux/err.h>
#include <linux/sched.h>
+#include <linux/sched/task_stack.h>
#include <linux/kconfig.h>
#include <linux/unistd.h>
#include <linux/dovetail.h>
@@ -269,6 +270,46 @@ static COBALT_SYSCALL(serialdbg, current,
return 0;
}
+static COBALT_SYSCALL(sigreturn, current, (void))
+{
+ struct pt_regs *regs = task_pt_regs(current);
+ sigset_t *blocked;
+ int ret;
+
+ ret = dovetail_restore_rt_signal_frame(regs);
+ if (ret < 0) {
+ struct xnthread *thread = xnthread_current();
+ spl_t s;
+
+ xnlock_get_irqsave(&nklock, s);
+
+ xnthread_set_info(thread, XNKICKED);
+ __xnthread_signal(thread, SIGSEGV, 0);
+
+ xnlock_put_irqrestore(&nklock, s);
+ return ret;
+ }
+
+ blocked = &xnthread_current()->sigblocked;
+ sigdelset(blocked, ret);
+
+ return __xn_reg_rval(regs);
+}
+
+static COBALT_SYSCALL(sigaction, current, (int sig, void __user *handler,
+ void __user *restorer))
+{
+ struct cobalt_ppd *sys_ppd = cobalt_ppd_get(0);
+
+ if (sig < 0 || sig >= _NSIG || !xnarch_is_supported_signal(sig))
+ return -EINVAL;
+
+ sys_ppd->sighand[sig] = handler;
+ sys_ppd->sigrestorer = restorer;
+
+ return 0;
+}
+
static void stringify_feature_set(unsigned long fset, char *buf, int size)
{
unsigned long feature;
diff --git a/kernel/cobalt/thread.c b/kernel/cobalt/thread.c
index bdd053140..367726e0d 100644
--- a/kernel/cobalt/thread.c
+++ b/kernel/cobalt/thread.c
@@ -20,6 +20,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
+#include <linux/dovetail.h>
#include <linux/kthread.h>
#include <linux/wait.h>
#include <linux/signal.h>
@@ -42,6 +43,7 @@
#include <pipeline/kevents.h>
#include <pipeline/sched.h>
#include <trace/events/cobalt-core.h>
+#include "posix/process.h"
#include "debug.h"
static DECLARE_WAIT_QUEUE_HEAD(join_all);
@@ -287,6 +289,7 @@ int __xnthread_init(struct xnthread *thread,
init_completion(&thread->exited);
memset(xnthread_archtcb(thread), 0, sizeof(struct xnarchtcb));
memset(thread->sigarray, 0, sizeof(thread->sigarray));
+ sigemptyset(&thread->sigblocked);
gravity = flags & XNUSER ? XNTIMER_UGRAVITY : XNTIMER_KGRAVITY;
xntimer_init(&thread->rtimer, &nkclock, timeout_handler,
@@ -2511,6 +2514,62 @@ int xnthread_killall(int grace, int mask)
}
EXPORT_SYMBOL_GPL(xnthread_killall);
+__weak int xnarch_setup_trap_info(unsigned int vector, struct pt_regs *regs,
+ int *sig, struct kernel_siginfo *info)
+{
+ return -ENOSYS;
+}
+
+__weak void xnarch_fixup_trap_regs(struct pt_regs *regs)
+{
+}
+
+__weak bool xnarch_is_supported_signal(int sig)
+{
+ return -EINVAL;
+}
+
+bool xnthread_handle_rt_signals(unsigned int trapnr, struct pt_regs *regs)
+{
+ struct cobalt_ppd *sys_ppd;
+ struct kernel_siginfo si;
+ struct ksignal ksig;
+ sigset_t *blocked;
+ int sig, ret;
+
+ ret = xnarch_setup_trap_info(trapnr, regs, &sig, &si);
+ if (ret)
+ return false;
+
+ sys_ppd = cobalt_ppd_get(0);
+ if (sys_ppd->sighand[sig] == NULL ||
+ sys_ppd->sighand[sig] == SIG_DFL ||
+ sys_ppd->sighand[sig] == SIG_IGN ||
+ sys_ppd->sighand[sig] == SIG_ERR)
+ return false;
+
+ blocked = &xnthread_current()->sigblocked;
+ if (sigismember(blocked, sig)) {
+ return false;
+ }
+
+ ksig.sig = sig;
+ memcpy(&ksig.info, &si, sizeof(si));
+ ksig.ka.sa.sa_flags = SA_SIGINFO | SA_RESTORER;
+ ksig.ka.sa.sa_restorer = sys_ppd->sigrestorer;
+ ksig.ka.sa.sa_handler = sys_ppd->sighand[sig];
+
+ ret = dovetail_setup_rt_signal_frame(&ksig, regs);
+ if (ret)
+ return false;
+
+ sigaddset(blocked, sig);
+
+ xnarch_fixup_trap_regs(regs);
+
+ return true;
+}
+
/* Xenomai's generic personality. */
struct xnthread_personality xenomai_personality = {
.name = "core",
diff --git a/kernel/cobalt/trace/cobalt-posix.h b/kernel/cobalt/trace/cobalt-posix.h
index 41bbb04b9..6c5691d8c 100644
--- a/kernel/cobalt/trace/cobalt-posix.h
+++ b/kernel/cobalt/trace/cobalt-posix.h
@@ -172,7 +172,9 @@
__cobalt_symbolic_syscall(timer_gettime64), \
__cobalt_symbolic_syscall(timerfd_settime64), \
__cobalt_symbolic_syscall(timerfd_gettime64), \
- __cobalt_symbolic_syscall(pselect64))
+ __cobalt_symbolic_syscall(pselect64), \
+ __cobalt_symbolic_syscall(sigreturn), \
+ __cobalt_symbolic_syscall(sigaction))
DECLARE_EVENT_CLASS(cobalt_syscall_entry,
TP_PROTO(unsigned int nr),
diff --git a/lib/cobalt/signal.c b/lib/cobalt/signal.c
index 6e40a3680..d6a95c96e 100644
--- a/lib/cobalt/signal.c
+++ b/lib/cobalt/signal.c
@@ -125,3 +125,22 @@ COBALT_IMPL(int, sigqueue, (pid_t pid, int sig, const union sigval value))
return 0;
}
+
+XENOMAI_BUILD_SIGRETURN();
+
+extern void cobalt_sigreturn(void) __asm__ ("__cobalt_sigreturn")
+ __attribute__((visibility("hidden")));
+
+int cobalt_rt_signal(int sig, void (*handler)(int, siginfo_t *, void *))
+{
+ int ret;
+
+ ret = XENOMAI_SYSCALL3(sc_cobalt_sigaction, sig, handler,
+ cobalt_sigreturn);
+ if (ret) {
+ errno = -ret;
+ return -1;
+ }
+
+ return 0;
+}
--
2.48.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 5/6] testsuite: smokey: Add testcases for signals
2025-04-08 12:28 [RFC PATCH 0/6] Xenomai: Real-time Exception Handling Nikolaus Funk
` (3 preceding siblings ...)
2025-04-08 12:28 ` [PATCH 4/6] cobalt: Add signal core code Nikolaus Funk
@ 2025-04-08 12:28 ` Nikolaus Funk
2025-04-08 12:28 ` [PATCH 6/6] utils: Add rt_signal_hist Nikolaus Funk
2025-04-08 17:32 ` [RFC PATCH 0/6] Xenomai: Real-time Exception Handling Jan Kiszka
6 siblings, 0 replies; 10+ messages in thread
From: Nikolaus Funk @ 2025-04-08 12:28 UTC (permalink / raw)
To: xenomai; +Cc: richard, Lorenz Kofler, Johannes Kirchmair
From: Lorenz Kofler <lorenz@sigma-star.at>
Adding multiple testcases to the smokey testsuite to ensure signal
handling works properly.
Test scenarios:
- Default: Ensure SIGILL handling works.
- TEST_FPE: Ensure SIGFPE handling works.
- TEST_NESTING_SAME_SIGNAL: Ensure nested signals of the same type are
not allowed.
- TEST_NESTING_DIFFERENT SIGNALS: Ensure nested signals of different
types are allowed and are handled successfully.
- TEST_MULTIPLE_ILLS: Ensure multiple SIGILLs after each other are
handled successfully.
- TEST_UNSUPPORTED_SIGNAL: Ensure registering of an unsupported signal
fails.
All test can be executed with: smokey --run=rtsignals.
Co-developed-by: Johannes Kirchmair <johannes.kirchmair@sigmatek.at>
Signed-off-by: Lorenz Kofler <lorenz@sigma-star.at>
---
configure.ac | 2 +
testsuite/smokey/Makefile.am | 2 +
testsuite/smokey/rtsignals/Makefile.am | 57 +++
testsuite/smokey/rtsignals/rtsignals.c | 35 ++
testsuite/smokey/rtsignals/rtsignals_test.c | 370 ++++++++++++++++++++
5 files changed, 466 insertions(+)
create mode 100644 testsuite/smokey/rtsignals/Makefile.am
create mode 100644 testsuite/smokey/rtsignals/rtsignals.c
create mode 100644 testsuite/smokey/rtsignals/rtsignals_test.c
diff --git a/configure.ac b/configure.ac
index aa3794a5f..678e8ef1e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -174,6 +174,7 @@ esac
AC_MSG_RESULT([$target_cpu_arch])
XENO_TARGET_ARCH=$target_cpu_arch
AM_CONDITIONAL(XENO_X86,[test x$target_cpu_arch = xx86])
+AM_CONDITIONAL(XENO_ARM, [test x$target_cpu_arch = xarm64 || test x$target_cpu_arch = xarm])
AC_ENABLE_SHARED
AC_PROG_LIBTOOL
@@ -1102,6 +1103,7 @@ AC_CONFIG_FILES([ \
testsuite/smokey/alchemytests/Makefile \
testsuite/smokey/psostests/Makefile \
testsuite/smokey/vxworkstests/Makefile \
+ testsuite/smokey/rtsignals/Makefile \
testsuite/clocktest/Makefile \
testsuite/xeno-test/Makefile \
utils/Makefile \
diff --git a/testsuite/smokey/Makefile.am b/testsuite/smokey/Makefile.am
index c49a5d77f..5bfe10491 100644
--- a/testsuite/smokey/Makefile.am
+++ b/testsuite/smokey/Makefile.am
@@ -41,6 +41,7 @@ COBALT_SUBDIRS = \
xddp \
y2038 \
alchemytests \
+ rtsignals \
vxworkstests \
psostests
@@ -86,6 +87,7 @@ DIST_SUBDIRS = \
xddp \
y2038 \
alchemytests \
+ rtsignals \
vxworkstests \
psostests
diff --git a/testsuite/smokey/rtsignals/Makefile.am b/testsuite/smokey/rtsignals/Makefile.am
new file mode 100644
index 000000000..8d2d6908c
--- /dev/null
+++ b/testsuite/smokey/rtsignals/Makefile.am
@@ -0,0 +1,57 @@
+testdir = @XENO_TEST_DIR@
+noinst_LIBRARIES = librtsignals.a
+
+librtsignals_a_SOURCES = rtsignals.c
+librtsignals_a_CPPFLAGS = \
+ $(XENO_USER_CFLAGS) \
+ -I$(top_srcdir)/include \
+ -DXENO_TEST_DIR='"$(XENO_TEST_DIR)"'
+
+CCLD = $(top_srcdir)/scripts/wrap-link.sh $(CC)
+
+test_PROGRAMS = rtsignals_signesting_same_signal rtsignals_multiple_ills rtsignals_unsupported_signal rtsignals_sigill
+if XENO_X86
+ test_PROGRAMS += rtsignals_sigfpe rtsignals_signesting_different_signals
+endif
+
+alchemycppflags = \
+ $(XENO_USER_CFLAGS) \
+ -I$(top_srcdir)/include
+
+alchemyldadd = \
+ $(XENO_POSIX_WRAPPERS) \
+ ../../../lib/alchemy/libalchemy.la \
+ ../../../lib/copperplate/libcopperplate.la \
+ @XENO_CORE_LDADD@ \
+ @XENO_USER_LDADD@ \
+ -lrt -lpthread -lm
+
+rtsignals_sigill_SOURCES = rtsignals_test.c
+rtsignals_sigill_CPPFLAGS = $(alchemycppflags)
+rtsignals_sigill_LDADD = $(alchemyldadd)
+rtsignals_sigill_LDFLAGS = @XENO_AUTOINIT_LDFLAGS@
+
+rtsignals_sigfpe_SOURCES = rtsignals_test.c
+rtsignals_sigfpe_CPPFLAGS = $(alchemycppflags) -DTEST_FPE=1
+rtsignals_sigfpe_LDADD = $(alchemyldadd)
+rtsignals_sigfpe_LDFLAGS = @XENO_AUTOINIT_LDFLAGS@
+
+rtsignals_signesting_same_signal_SOURCES = rtsignals_test.c
+rtsignals_signesting_same_signal_CPPFLAGS = $(alchemycppflags) -DTEST_NESTING_SAME_SIGNAL=1
+rtsignals_signesting_same_signal_LDADD = $(alchemyldadd)
+rtsignals_signesting_same_signal_LDFLAGS = @XENO_AUTOINIT_LDFLAGS@
+
+rtsignals_signesting_different_signals_SOURCES = rtsignals_test.c
+rtsignals_signesting_different_signals_CPPFLAGS = $(alchemycppflags) -DTEST_NESTING_DIFFERENT_SIGNALS=1
+rtsignals_signesting_different_signals_LDADD = $(alchemyldadd)
+rtsignals_signesting_different_signals_LDFLAGS = @XENO_AUTOINIT_LDFLAGS@
+
+rtsignals_multiple_ills_SOURCES = rtsignals_test.c
+rtsignals_multiple_ills_CPPFLAGS = $(alchemycppflags) -DTEST_MULTIPLE_ILLS=1
+rtsignals_multiple_ills_LDADD = $(alchemyldadd)
+rtsignals_multiple_ills_LDFLAGS = @XENO_AUTOINIT_LDFLAGS@
+
+rtsignals_unsupported_signal_SOURCES = rtsignals_test.c
+rtsignals_unsupported_signal_CPPFLAGS = $(alchemycppflags) -DTEST_UNSUPPORTED_SIGNAL=1
+rtsignals_unsupported_signal_LDADD = $(alchemyldadd)
+rtsignals_unsupported_signal_LDFLAGS = @XENO_AUTOINIT_LDFLAGS@
diff --git a/testsuite/smokey/rtsignals/rtsignals.c b/testsuite/smokey/rtsignals/rtsignals.c
new file mode 100644
index 000000000..8d797861f
--- /dev/null
+++ b/testsuite/smokey/rtsignals/rtsignals.c
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <string.h>
+#include <smokey/smokey.h>
+
+static const char * const tests[] = {
+ "rtsignals_multiple_ills",
+ "rtsignals_unsupported_signal",
+ "rtsignals_sigill",
+ "rtsignals_signesting_same_signal",
+#if defined(__i386__) || defined(__x86_64__)
+ "rtsignals_signesting_different_signals",
+ "rtsignals_sigfpe",
+#elif defined(__arm__) || defined(__aarch64__)
+#endif
+};
+
+static int run_rtsignals(struct smokey_test *t, int argc, char *const argv[])
+{
+ int test_ret = 0;
+ int ret = 0;
+ int tmp;
+
+ for (size_t i = 0; i < ARRAY_SIZE(tests); i++) {
+ tmp = smokey_run_extprog(XENO_TEST_DIR, tests[i],
+ "--cpu-affinity=0", &test_ret);
+ if (test_ret)
+ ret = test_ret; /* Return the last failed test result */
+ if (tmp)
+ break;
+ }
+
+ return ret;
+}
+smokey_test_plugin(rtsignals, SMOKEY_NOARGS, "Run external rtsignalstest");
+
diff --git a/testsuite/smokey/rtsignals/rtsignals_test.c b/testsuite/smokey/rtsignals/rtsignals_test.c
new file mode 100644
index 000000000..1140ce8e3
--- /dev/null
+++ b/testsuite/smokey/rtsignals/rtsignals_test.c
@@ -0,0 +1,370 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <ucontext.h>
+#include <copperplate/traceobj.h>
+#include <alchemy/task.h>
+#include <assert.h>
+#include <setjmp.h>
+#include <stdatomic.h>
+
+#include <execinfo.h>
+#include <signal.h>
+#include <pthread.h>
+
+static void sigdebug_handler(int sig, siginfo_t *info, void *context);
+static void linux_handler(int sig, siginfo_t *info, void *context);
+static void rt_test_handler(int sig, siginfo_t *info, void *context);
+static void basic_rt_handler(int sig, siginfo_t *info, void *context);
+
+//#define DEBUG
+#define MULTIPLE_SIGILL 100
+#define CHECK_BIT(bit) check_bit(bit, #bit)
+
+// expected status bits:
+#define BIT_RT_HANDLER_ENTERED (1<<0)
+#define BIT_RT_HANDLER_FINISHED (1<<1)
+#define BIT_RT_HANDLER_WRONG_TASK (1<<2)
+#define BIT_RT_HANDLER_WRONG_SIGNAL (1<<3)
+#define BIT_DOMAIN_SWITCH (1<<4)
+#define BIT_LINUX_HANDLER_FINISHED (1<<5)
+#define BIT_RT_TASK_FINSIHED (1<<6)
+#define BIT_BASIC_RT_HANDLER_FINISHED (1<<7)
+
+static RT_TASK task;
+static sig_atomic_t status;
+static sig_atomic_t cause;
+
+struct sig_handler {
+ int signal;
+ void (*handler)(int, siginfo_t *, void *);
+};
+
+/*
+ * Test scenarios:
+ * - Default: Ensure SIGILL handling works.
+ * - TEST_FPE: Ensure SIGFPE handling works.
+ * - TEST_NESTING_SAME_SIGNAL Ensure nested signals of the same type are not
+ * allowed.
+ * - TEST_NESTING_DIFFERENT SIGNALS:
+ * Ensure nested signals of different types are allowed
+ * and are handled successfully.
+ * - TEST_MULTIPLE_ILLS Ensure multiple SIGILLs after each other are handled
+ * successfully.
+ * - TEST_UNSUPPORTED_SIGNAL Ensure registering of an unsupported signal fails.
+ */
+#if defined(TEST_NESTING_SAME_SIGNAL)
+#define TEST_SIGNAL SIGILL
+#define TEST_SIGNAL_NESTED SIGILL
+static const struct sig_handler linux_handlers[] = {
+ {SIGDEBUG, sigdebug_handler},
+ {SIGILL, linux_handler},
+};
+static const struct sig_handler rt_handlers[] = {
+ {SIGILL, rt_test_handler},
+};
+static int expected_status = BIT_RT_HANDLER_ENTERED
+ | BIT_RT_HANDLER_FINISHED
+ | BIT_DOMAIN_SWITCH
+ | BIT_LINUX_HANDLER_FINISHED
+ | BIT_RT_TASK_FINSIHED;
+
+#elif defined(TEST_UNSUPPORTED_SIGNAL)
+#define TEST_SIGNAL SIGSEGV
+static const struct sig_handler linux_handlers[] = {
+ {SIGDEBUG, sigdebug_handler},
+ {SIGILL, linux_handler},
+};
+static const struct sig_handler rt_handlers[] = {
+ {SIGSEGV, rt_test_handler},
+};
+static int expected_status = 0;
+
+#elif defined(TEST_NESTING_DIFFERENT_SIGNALS)
+#define TEST_SIGNAL SIGFPE
+#define TEST_SIGNAL_NESTED SIGILL
+static int expected_status = BIT_RT_HANDLER_ENTERED
+ | BIT_RT_HANDLER_FINISHED
+ | BIT_RT_TASK_FINSIHED
+ | BIT_BASIC_RT_HANDLER_FINISHED;
+static const struct sig_handler linux_handlers[] = {
+ {SIGDEBUG, sigdebug_handler},
+ {SIGILL, linux_handler},
+ {SIGFPE, linux_handler},
+};
+static const struct sig_handler rt_handlers[] = {
+ {SIGFPE, rt_test_handler},
+ {SIGILL, basic_rt_handler},
+};
+
+#elif defined(TEST_MULTIPLE_ILLS)
+#define TEST_SIGNAL SIGILL
+static const struct sig_handler linux_handlers[] = {
+ {SIGDEBUG, sigdebug_handler},
+ {SIGILL, linux_handler},
+};
+static const struct sig_handler rt_handlers[] = {
+ {SIGILL, rt_test_handler},
+};
+static int expected_status = BIT_RT_HANDLER_ENTERED
+ | BIT_RT_HANDLER_FINISHED
+ | BIT_RT_TASK_FINSIHED;
+
+#elif defined(TEST_FPE)
+#define TEST_SIGNAL SIGFPE
+static const struct sig_handler linux_handlers[] = {
+ {SIGDEBUG, sigdebug_handler},
+ {SIGFPE, linux_handler},
+};
+static const struct sig_handler rt_handlers[] = {
+ {SIGFPE, rt_test_handler},
+};
+static int expected_status = BIT_RT_HANDLER_ENTERED
+ | BIT_RT_HANDLER_FINISHED
+ | BIT_RT_TASK_FINSIHED;
+
+#else /* Default Test */
+#define TEST_SIGNAL SIGILL
+static const struct sig_handler linux_handlers[] = {
+ {SIGDEBUG, sigdebug_handler},
+ {SIGILL, linux_handler},
+};
+static const struct sig_handler rt_handlers[] = {
+ {SIGILL, rt_test_handler},
+};
+static int expected_status = BIT_RT_HANDLER_ENTERED
+ | BIT_RT_HANDLER_FINISHED
+ | BIT_RT_TASK_FINSIHED;
+
+#endif
+
+#define NUM_LINUX_HANDLERS (sizeof(linux_handlers) / sizeof(linux_handlers[0]))
+#define NUM_RT_HANDLERS (sizeof(rt_handlers) / sizeof(rt_handlers[0]))
+
+static void debug_log(const char *format, ...) {
+#ifdef DEBUG
+ va_list args;
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+#endif
+}
+
+static bool __maybe_unused check_bit(int bit, const char *bit_name){
+ if ((status & bit) == (expected_status & bit))
+ return true;
+
+ fprintf(stderr, "%s not as expected.\n", bit_name);
+ return false;
+}
+
+static int test_successful(void)
+{
+ if (status == expected_status) {
+ debug_log("Test passed\n", stderr);
+ return 1;
+ }
+ debug_log("Test not passed\n", stderr);
+#ifdef DEBUG
+ static const char * const sigdebug_msg[] = {
+ [SIGDEBUG_UNDEFINED] = "latency: received SIGXCPU for unknown reason",
+ [SIGDEBUG_MIGRATE_SIGNAL] = "received signal",
+ [SIGDEBUG_MIGRATE_SYSCALL] = "invoked syscall",
+ [SIGDEBUG_MIGRATE_FAULT] = "triggered fault",
+ [SIGDEBUG_MIGRATE_PRIOINV] = "affected by priority inversion",
+ [SIGDEBUG_NOMLOCK] = "Xenomai: process memory not locked (missing mlockall?)",
+ [SIGDEBUG_WATCHDOG] = "Xenomai: watchdog triggered (period too short?)",
+ };
+
+ CHECK_BIT(BIT_RT_HANDLER_ENTERED);
+ CHECK_BIT(BIT_RT_HANDLER_FINISHED);
+ CHECK_BIT(BIT_RT_HANDLER_WRONG_TASK);
+ CHECK_BIT(BIT_RT_HANDLER_WRONG_SIGNAL);
+ if (!CHECK_BIT(BIT_DOMAIN_SWITCH)){
+ if (expected_status & BIT_DOMAIN_SWITCH)
+ debug_log("- Cause: Domain switch should have happend.\n");
+ else
+ debug_log("- Caused by: %s\n", sigdebug_msg[cause]);
+ }
+ CHECK_BIT(BIT_LINUX_HANDLER_FINISHED);
+ CHECK_BIT(BIT_RT_TASK_FINSIHED);
+ CHECK_BIT(BIT_BASIC_RT_HANDLER_FINISHED);
+#endif
+
+ return 0;
+}
+
+static void register_signal_handler(int signal, void (*handler)(int, siginfo_t *, void *)) {
+ struct sigaction sa;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = handler;
+ sa.sa_flags = SA_SIGINFO;
+ if (sigaction(signal, &sa, NULL) == -1) {
+ perror("Failed to register Linux handler");
+ }
+}
+
+inline static void do_ill(void)
+{
+#if defined(__i386__) || defined(__x86_64__)
+ __asm__("ud2");
+#else
+ __asm__("udf #0xdead");
+#endif
+}
+
+static void do_fpe(void)
+{
+#if defined(__i386__) || defined(__x86_64__)
+ __asm__("xorl %%eax, %%eax\n\t"
+ "movl %%eax, %%ecx\n\t"
+ "cltd\n\t"
+ "idivl %%ecx"
+ : : : "eax", "ecx");
+#endif
+}
+
+static void do_cleanup(void *context)
+{
+ int step = 0;
+ ucontext_t *uc = context;
+
+#if defined(__i386__) || defined(__x86_64__)
+ /*
+ * do_fpe(): idivl %ecx 2 bytes long
+ * do_ill(): ud2 2 bytes long
+ */
+ step = 2;
+#else
+ // do_ill(): udf #0xdead 4 bytes long
+ step = 4;
+#endif
+
+#if defined(__i386__)
+ uc->uc_mcontext.gregs[REG_EIP] += step;
+#elif defined(__x86_64__)
+ uc->uc_mcontext.gregs[REG_RIP] += step;
+#elif defined(__aarch64__)
+ uc->uc_mcontext.pc += step;
+#elif defined(__arm__)
+ uc->uc_mcontext.arm_pc += step;
+#endif
+}
+
+static void __maybe_unused linux_handler(int sig, siginfo_t *info, void *context)
+{
+ do_cleanup(context);
+ status |= BIT_LINUX_HANDLER_FINISHED;
+}
+
+static void __maybe_unused basic_rt_handler(int sig, siginfo_t *info, void *context)
+{
+ do_cleanup(context);
+ status |= BIT_BASIC_RT_HANDLER_FINISHED;
+}
+
+static void __maybe_unused sigdebug_handler(int sig, siginfo_t *info, void *context)
+{
+ cause = sigdebug_reason(info);
+ if (cause > SIGDEBUG_WATCHDOG)
+ cause = SIGDEBUG_UNDEFINED;
+
+ status |= BIT_DOMAIN_SWITCH;
+}
+
+static void __maybe_unused rt_test_handler(int sig, siginfo_t *info, void *context)
+{
+ RT_TASK *self;
+ (void)context;
+
+ status |= BIT_RT_HANDLER_ENTERED;
+ if (sig != TEST_SIGNAL) {
+ status |= BIT_RT_HANDLER_WRONG_SIGNAL;
+ return;
+ }
+ atomic_signal_fence(memory_order_seq_cst);
+
+#ifdef TEST_SIGNAL_NESTED
+ switch (TEST_SIGNAL_NESTED) {
+ case SIGILL:
+ do_ill();
+ break;
+ default:
+ break;
+ }
+#endif
+
+ atomic_signal_fence(memory_order_seq_cst);
+
+ self = rt_task_self();
+ if (self == NULL || !rt_task_same(self, &task))
+ status |= BIT_RT_HANDLER_WRONG_TASK;
+ else
+ status |= BIT_RT_HANDLER_FINISHED;
+
+ do_cleanup(context);
+}
+
+
+static void task_proc(void *arg)
+{
+ int ret;
+
+ // Register rt-signal handlers
+ for (size_t i = 0; i < NUM_RT_HANDLERS; i++) {
+ ret = cobalt_rt_signal(rt_handlers[i].signal, rt_handlers[i].handler);
+ if (ret != 0)
+ return;
+ }
+
+ // trigger fault
+ switch(TEST_SIGNAL) {
+ case SIGILL:
+ do_ill();
+ break;
+ case MULTIPLE_SIGILL:
+ do_ill();
+ do_ill();
+ do_ill();
+ break;
+ case SIGFPE:
+ do_fpe();
+ break;
+ default:
+ break;
+ }
+
+ atomic_signal_fence(memory_order_seq_cst);
+
+ // clear T_WARNSW so that rt_task_delete() does not send SIGDEBUG
+ rt_task_set_mode(T_WARNSW, 0, 0);
+
+ status |= BIT_RT_TASK_FINSIHED;
+}
+
+int main(void)
+{
+ int ret;
+
+ // Setup Linux handlers
+ for (size_t i = 0; i < NUM_LINUX_HANDLERS; i++) {
+ register_signal_handler(linux_handlers[i].signal, linux_handlers[i].handler);
+ }
+
+ // Run RT Task
+ ret = rt_task_create(&task, "rt-task", 0, 20, T_JOINABLE | T_WARNSW);
+ assert(ret == 0);
+
+ ret = rt_task_start(&task, task_proc, NULL);
+ assert(ret == 0);
+
+ ret = rt_task_join(&task);
+ assert(ret == 0);
+
+ (void)ret;
+
+ return test_successful() ? EXIT_SUCCESS : EXIT_FAILURE;
+}
--
2.48.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 6/6] utils: Add rt_signal_hist
2025-04-08 12:28 [RFC PATCH 0/6] Xenomai: Real-time Exception Handling Nikolaus Funk
` (4 preceding siblings ...)
2025-04-08 12:28 ` [PATCH 5/6] testsuite: smokey: Add testcases for signals Nikolaus Funk
@ 2025-04-08 12:28 ` Nikolaus Funk
2025-04-08 17:32 ` [RFC PATCH 0/6] Xenomai: Real-time Exception Handling Jan Kiszka
6 siblings, 0 replies; 10+ messages in thread
From: Nikolaus Funk @ 2025-04-08 12:28 UTC (permalink / raw)
To: xenomai; +Cc: richard, Lorenz Kofler, Johannes Kirchmair
From: Lorenz Kofler <lorenz@sigma-star.at>
Useful to create a histogram to evaluate RT signal handling performance.
The program will output a file called hist.txt in the format:
TIME in Nanoseconds, Frequency
Co-developed-by: Johannes Kirchmair <johannes.kirchmair@sigmatek.at>
Signed-off-by: Lorenz Kofler <lorenz@sigma-star.at>
---
configure.ac | 1 +
utils/Makefile.am | 2 +-
utils/rt_signal_hist/Makefile.am | 22 +++
utils/rt_signal_hist/error.h | 15 ++
utils/rt_signal_hist/histo.c | 47 +++++
utils/rt_signal_hist/histo.h | 14 ++
utils/rt_signal_hist/result.c | 17 ++
utils/rt_signal_hist/result.h | 13 ++
utils/rt_signal_hist/rt_signal_hist.c | 237 ++++++++++++++++++++++++++
9 files changed, 367 insertions(+), 1 deletion(-)
create mode 100644 utils/rt_signal_hist/Makefile.am
create mode 100644 utils/rt_signal_hist/error.h
create mode 100644 utils/rt_signal_hist/histo.c
create mode 100644 utils/rt_signal_hist/histo.h
create mode 100644 utils/rt_signal_hist/result.c
create mode 100644 utils/rt_signal_hist/result.h
create mode 100644 utils/rt_signal_hist/rt_signal_hist.c
diff --git a/configure.ac b/configure.ac
index 678e8ef1e..325946a2c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1114,6 +1114,7 @@ AC_CONFIG_FILES([ \
utils/slackspot/Makefile \
utils/corectl/Makefile \
utils/autotune/Makefile \
+ utils/rt_signal_hist/Makefile \
utils/net/rtnet \
utils/net/rtnet.conf \
utils/net/Makefile \
diff --git a/utils/Makefile.am b/utils/Makefile.am
index 4de6434a9..79c39ac90 100644
--- a/utils/Makefile.am
+++ b/utils/Makefile.am
@@ -1,5 +1,5 @@
SUBDIRS = hdb
if XENO_COBALT
-SUBDIRS += analogy autotune can net ps slackspot corectl
+SUBDIRS += analogy autotune can net ps slackspot corectl rt_signal_hist
endif
SUBDIRS += chkkconf
diff --git a/utils/rt_signal_hist/Makefile.am b/utils/rt_signal_hist/Makefile.am
new file mode 100644
index 000000000..810a63bba
--- /dev/null
+++ b/utils/rt_signal_hist/Makefile.am
@@ -0,0 +1,22 @@
+testdir = @XENO_TEST_DIR@
+
+CCLD = $(top_srcdir)/scripts/wrap-link.sh $(CC)
+
+test_PROGRAMS = rt_signal_hist
+
+alchemycppflags = \
+ $(XENO_USER_CFLAGS) \
+ -I$(top_srcdir)/include
+
+alchemyldadd = \
+ @XENO_AUTOINIT_LDFLAGS@ \
+ $(XENO_POSIX_WRAPPERS) \
+ ../../lib/alchemy/libalchemy.la \
+ ../../lib/copperplate/libcopperplate.la \
+ @XENO_CORE_LDADD@ \
+ @XENO_USER_LDADD@ \
+ -lrt -lpthread -lm
+
+rt_signal_hist_SOURCES = rt_signal_hist.c histo.c result.c
+rt_signal_hist_CPPFLAGS = $(alchemycppflags)
+rt_signal_hist_LDADD = $(alchemyldadd)
diff --git a/utils/rt_signal_hist/error.h b/utils/rt_signal_hist/error.h
new file mode 100644
index 000000000..811ee642c
--- /dev/null
+++ b/utils/rt_signal_hist/error.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef ERROR_EXIT_H
+#define ERROR_EXIT_H
+
+#include <stdio.h>
+#include <stdlib.h>
+
+static int error(char *reason, int ret)
+{
+ printf("%s: err= %d\n", reason, ret);
+ exit(1);
+}
+
+#endif
+
diff --git a/utils/rt_signal_hist/histo.c b/utils/rt_signal_hist/histo.c
new file mode 100644
index 000000000..5667e62f3
--- /dev/null
+++ b/utils/rt_signal_hist/histo.c
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "histo.h"
+#include "error.h"
+
+void initHisto(struct histo **histo, unsigned long max_entry)
+{
+ unsigned long i = 0;
+ *histo = malloc(sizeof(struct histo) + max_entry * sizeof(unsigned long));
+ if (!histo)
+ return;
+
+ for (i = 0; i < max_entry; ++i)
+ (*histo)->data[i] = 0;
+
+ (*histo)->max_index = 0;
+ (*histo)->max_entry = max_entry;
+}
+
+void writeHisto(struct histo *histo)
+{
+ unsigned long i;
+ FILE *f = fopen("hist.txt", "w");
+
+ if (!f)
+ error("can't open \"hist.txt\"\n", errno);
+
+ for (i = 0; i <= histo->max_index; ++i) {
+ if (histo->data[i] > 0)
+ fprintf(f, "%lu %lu\n", i, histo->data[i]);
+ }
+ fclose(f);
+}
+
+void updateHisto(struct histo *histo, unsigned long curr)
+{
+ unsigned long index;
+
+ index = curr;
+ index = index >= histo->max_entry ? histo->max_entry - 1 : index;
+ histo->max_index = histo->max_index >= index ? histo->max_index : index;
+ histo->data[index]++;
+}
+
diff --git a/utils/rt_signal_hist/histo.h b/utils/rt_signal_hist/histo.h
new file mode 100644
index 000000000..8ff92fce4
--- /dev/null
+++ b/utils/rt_signal_hist/histo.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef HISTO_H
+#define HISTO_H
+
+struct histo {
+ unsigned long max_entry;
+ unsigned long max_index;
+ unsigned long data[];
+};
+
+void initHisto(struct histo **histo, unsigned long n);
+void writeHisto(struct histo *histo);
+void updateHisto(struct histo *histo, unsigned long curr);
+#endif
diff --git a/utils/rt_signal_hist/result.c b/utils/rt_signal_hist/result.c
new file mode 100644
index 000000000..db8c99beb
--- /dev/null
+++ b/utils/rt_signal_hist/result.c
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "result.h"
+
+void initResult(struct result *resu)
+{
+ resu->min = (unsigned long)-1l;
+ resu->max = 0ul;
+ resu->avr = 0ul;
+}
+
+void updateResult(struct result *resu, unsigned long curr, unsigned long ith_entry)
+{
+ resu->min = curr < resu->min ? curr : resu->min;
+ resu->max = curr > resu->max ? curr : resu->max;
+ resu->avr = (resu->avr * (ith_entry - 1) + curr) / ith_entry;
+}
+
diff --git a/utils/rt_signal_hist/result.h b/utils/rt_signal_hist/result.h
new file mode 100644
index 000000000..5c164fa66
--- /dev/null
+++ b/utils/rt_signal_hist/result.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef RESULT_H
+#define RESULT_H
+
+struct result {
+ unsigned long min;
+ unsigned long max;
+ unsigned long avr;
+};
+
+void initResult(struct result *resu);
+void updateResult(struct result *resu, unsigned long curr, unsigned long ith_entry);
+#endif
diff --git a/utils/rt_signal_hist/rt_signal_hist.c b/utils/rt_signal_hist/rt_signal_hist.c
new file mode 100644
index 000000000..bfc8947aa
--- /dev/null
+++ b/utils/rt_signal_hist/rt_signal_hist.c
@@ -0,0 +1,237 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <stdio.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <ucontext.h>
+
+#include <alchemy/task.h>
+#include <cobalt/signal.h>
+#include <copperplate/clockobj.h>
+
+#include "histo.h"
+#include "result.h"
+#include "error.h"
+
+#define USE_GETTIME 0 // TODO: when is this needed?
+#define MAX_TIME 10000000
+
+static RT_TASK task;
+static const char *task_name = "signal_test_task";
+static const int prio = 80;
+static int TEST_SIGNAL = SIGILL;
+
+typedef struct {
+ const char *name;
+ int value;
+} SignalMapping;
+
+static const SignalMapping signals[] = {
+ {"SIGILL", SIGILL},
+ {"SIGTRAP", SIGTRAP},
+ {"SIGFPE", SIGFPE},
+ {"SIGSEGV", SIGSEGV},
+ {NULL, 0}
+};
+
+static int get_signal_value(const char *signal_name)
+{
+ for (int i = 0; signals[i].name != NULL; i++) {
+ if (strcmp(signals[i].name, signal_name) == 0)
+ return signals[i].value;
+ }
+ return -1;
+}
+
+static const char *get_signal_name(int signal_value)
+{
+ for (int i = 0; signals[i].name != NULL; i++) {
+ if (signals[i].value == signal_value)
+ return signals[i].name;
+ }
+ return "UNKNOWN_SIGNAL";
+}
+
+static int get_step(void)
+{
+#if defined(__i386__) || defined(__x86_64__)
+ // do_fpe: `idivl %ecx` is 2 bytes long
+ // do_ill: `ud2` is 2 bytes long
+ return 2;
+#else
+ // do_ill: `udf #0xdead` is 4 bytes long
+ return 4;
+#endif
+}
+
+static void do_cleanup(void *context)
+{
+ int step = 0;
+ ucontext_t *uc = context;
+
+ step = get_step();
+
+#if defined(__i386__)
+ uc->uc_mcontext.gregs[REG_EIP] += step;
+#elif defined(__x86_64__)
+ uc->uc_mcontext.gregs[REG_RIP] += step;
+#elif defined(__aarch64__)
+ uc->uc_mcontext.pc += step;
+#elif defined(__arm__)
+ uc->uc_mcontext.arm_pc += step;
+#else
+ #error "Unknown Architecture"
+#endif
+}
+
+static void sigdebug_handler(int sig, siginfo_t *info, void *context)
+{
+ printf("%s called, this should not happen\n", __func__);
+ exit(EXIT_FAILURE);
+}
+
+static void sighandler(int sig, siginfo_t *info, void *data)
+{
+ do_cleanup(data);
+}
+
+static void do_ill(void)
+{
+#if defined(__i386__) || defined(__x86_64__)
+ __asm__("ud2");
+#else
+ __asm__("udf #0xdead");
+#endif
+}
+
+static void do_fpe(void)
+{
+#if defined(__i386__) || defined(__x86_64__)
+ __asm__("xorl %%eax, %%eax\n\t"
+ "movl %%eax, %%ecx\n\t"
+ "cltd\n\t"
+ "idivl %%ecx"
+ : : : "eax", "ecx");
+#endif
+}
+
+static void printPreRunInfo(void)
+{
+ if (USE_GETTIME) {
+ struct timespec time;
+
+ clock_getres(CLOCK_MONOTONIC_RAW, &time);
+ printf("Using CLOCK_MONOTONIC_RAW: res_sec = %lld res_nsec = %ld\n",
+ (long long)time.tv_sec, time.tv_nsec);
+ return;
+ }
+
+ printf("USING Xenomai rt_timer: res_nsec = %lld\n", rt_timer_ticks2ns(1));
+}
+
+static inline unsigned long ns_now(void)
+{
+ if (USE_GETTIME) {
+ struct timespec time;
+
+ clock_gettime(CLOCK_MONOTONIC_RAW, &time);
+ return time.tv_nsec;
+ }
+
+ ticks_t ticks;
+
+ ticks = clockobj_get_ns();
+ return rt_timer_ticks2ns(ticks);
+}
+
+static void task_func(void *cookie)
+{
+ struct histo *histogram = (struct histo *)cookie;
+ struct result resu;
+
+ unsigned long start_time, end_time, diff_time;
+ int i, j, ret;
+ char error_message[80];
+
+ printPreRunInfo();
+
+ ret = cobalt_rt_signal(TEST_SIGNAL, sighandler);
+ if (ret) {
+ snprintf(error_message, sizeof(error_message),
+ "Failed to register rtsignal signal handler for signal %s",
+ get_signal_name(TEST_SIGNAL));
+ error(error_message, ret);
+ }
+
+ initResult(&resu);
+
+ for (j = 0; j < 10000; ++j) {
+ for (i = 0; i < 1000; ++i) {
+
+ start_time = ns_now();
+ if (TEST_SIGNAL == SIGILL)
+ do_ill();
+ else if (TEST_SIGNAL == SIGFPE)
+ do_fpe();
+ else
+ error("Unsupported signal encountered", TEST_SIGNAL);
+
+ end_time = ns_now();
+
+ if (end_time <= start_time) { // dismiss on counter overrun
+ continue;
+ }
+
+ diff_time = end_time - start_time;
+ //+1 as we add with index i the (i+1)th entry
+ updateResult(&resu, diff_time, i+1);
+ updateHisto(histogram, diff_time);
+ }
+
+ printf("%d: min = %lu max = %lu avr = %lu\n", j, resu.min, resu.max, resu.avr);
+ rt_task_sleep(1000000);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ int ret;
+ struct histo *histogram;
+ struct sigaction sa;
+
+ if (argc != 2) {
+ fprintf(stderr, "Usage: %s <signal>\n", argv[0]);
+ exit(1);
+ }
+
+ TEST_SIGNAL = get_signal_value(argv[1]);
+ if (TEST_SIGNAL < 0)
+ error("Signal not supported", TEST_SIGNAL);
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = sigdebug_handler;
+ sa.sa_flags = SA_SIGINFO | SA_NODEFER;
+ sigaction(SIGDEBUG, &sa, NULL);
+
+ initHisto(&histogram, MAX_TIME);
+ if (!histogram)
+ error("initHisto failed", -ENOMEM);
+
+ ret = rt_task_create(&task, task_name, 0, prio, T_JOINABLE | T_WARNSW);
+ if (ret)
+ error("rt_task_create failed", ret);
+
+ ret = rt_task_start(&task, task_func, histogram);
+ if (ret)
+ error("rt_start_task failed", ret);
+
+ rt_task_join(&task);
+ rt_task_delete(&task);
+
+ writeHisto(histogram);
+
+ return 0;
+}
+
--
2.48.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [RFC PATCH 0/6] Xenomai: Real-time Exception Handling
2025-04-08 12:28 [RFC PATCH 0/6] Xenomai: Real-time Exception Handling Nikolaus Funk
` (5 preceding siblings ...)
2025-04-08 12:28 ` [PATCH 6/6] utils: Add rt_signal_hist Nikolaus Funk
@ 2025-04-08 17:32 ` Jan Kiszka
2025-04-08 18:39 ` Richard Weinberger
6 siblings, 1 reply; 10+ messages in thread
From: Jan Kiszka @ 2025-04-08 17:32 UTC (permalink / raw)
To: Nikolaus Funk, xenomai; +Cc: richard, Richard Weinberger
On 08.04.25 14:28, Nikolaus Funk wrote:
> From: Richard Weinberger <richard@nod.at>
>
> Currently, any exception that occurs in primary mode triggers a switch
> to secondary mode, and Linux posts a signal.
> This change allows certain exceptions to be handled directly in the
> affected thread while remaining in primary mode.
>
> At present, only SIGILL (for x86, arm32 and arm64) and SIGFPE (for x86)
> are supported.
> Adding support for additional exceptions is possible but requires
> careful consideration, as not all exception types can be analyzed in
IIRC, we should be able to rather easily provide
ARM64_TRAP_ALIGN/ARM_TRAP_ALIGNMENT/SIGBUS as well.
> real-time. A notable example is a page fault, determining whether
> SIGSEGV is appropriate requires deep traversal into the memory
> management code.
...on arm and arm64. It worked fairly well for x86. This is indeed a
very prominent exception that people may expect behind this feature. And
it is also a use case we have with our (x86-only) deployment.
>
> Patches 1, 2, 3, and 4 implement the Xenomai-side changes for this
> feature. Dovetail will receive a separate patch set. Patches 5 and 6
> introduce tests.
>
> It is important to note that this is not a fully-fledged signal
> implementation. The only supported use case is delivering exceptions
> as signals to the affected thread.
> There is no support for sending signals or handling block/ignore masks.
> The only user visible API so far is cobalt_rt_signal().
> It takes a signal number (SIGILL or SIGFPE so far) and a handler
> function with the signature fn(int, siginfo_t *, void *).
Did you intentionally left out the oldact parameter of sigaction?
>
> TODO:
> - Better naming, IMHO "signal" is the wrong term and will confuse users.
> Especially since POSIX real-time signals are something different.
> Maybe "umex" for "user mode exception handling"?
Just "exception" might be enough and clearer. OTOH, we are reusing a lot
of sigaction and siginfo...
> - Document new APIs
> - Improve tests
> - Carefully select more exceptions
Yeah, that is the challenge.
And:
- align with EVL / Xenomai 4 to ensure compatible features
Jan
--
Siemens AG, Foundational Technologies
Linux Expert Center
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC PATCH 0/6] Xenomai: Real-time Exception Handling
2025-04-08 17:32 ` [RFC PATCH 0/6] Xenomai: Real-time Exception Handling Jan Kiszka
@ 2025-04-08 18:39 ` Richard Weinberger
2025-04-10 9:45 ` Philippe Gerum
0 siblings, 1 reply; 10+ messages in thread
From: Richard Weinberger @ 2025-04-08 18:39 UTC (permalink / raw)
To: Nikolaus Funk, xenomai, Jan Kiszka; +Cc: Richard Weinberger
On Dienstag, 8. April 2025 19:32 Jan Kiszka wrote:
> > real-time. A notable example is a page fault, determining whether
> > SIGSEGV is appropriate requires deep traversal into the memory
> > management code.
>
> ...on arm and arm64. It worked fairly well for x86. This is indeed a
> very prominent exception that people may expect behind this feature. And
> it is also a use case we have with our (x86-only) deployment.
True that.
I think the set of supported exceptions should be architecture specific
anyways. And we need to state that it is best effort.
>
> >
> > Patches 1, 2, 3, and 4 implement the Xenomai-side changes for this
> > feature. Dovetail will receive a separate patch set. Patches 5 and 6
> > introduce tests.
> >
> > It is important to note that this is not a fully-fledged signal
> > implementation. The only supported use case is delivering exceptions
> > as signals to the affected thread.
> > There is no support for sending signals or handling block/ignore masks.
> > The only user visible API so far is cobalt_rt_signal().
> > It takes a signal number (SIGILL or SIGFPE so far) and a handler
> > function with the signature fn(int, siginfo_t *, void *).
>
> Did you intentionally left out the oldact parameter of sigaction?
Not really. Adding this should be trivial.
Maybe my subconsciousness tried to make it less look like POSIX
real time signals. ;-)
>
> >
> > TODO:
> > - Better naming, IMHO "signal" is the wrong term and will confuse users.
> > Especially since POSIX real-time signals are something different.
> > Maybe "umex" for "user mode exception handling"?
>
> Just "exception" might be enough and clearer. OTOH, we are reusing a lot
> of sigaction and siginfo...
That's the problem. It kinda looks like signals but isn't.
>
> > - Document new APIs
> > - Improve tests
> > - Carefully select more exceptions
>
> Yeah, that is the challenge.
>
> And:
>
> - align with EVL / Xenomai 4 to ensure compatible features
Agreed.
The dovetail side is rather small. We could also integrate the signal frame
helper functions into Xenomai.
Thanks,
//richard
--
sigma star gmbh | Eduard-Bodem-Gasse 6, 6020 Innsbruck, AUT UID/VAT Nr:
ATU 66964118 | FN: 374287y
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC PATCH 0/6] Xenomai: Real-time Exception Handling
2025-04-08 18:39 ` Richard Weinberger
@ 2025-04-10 9:45 ` Philippe Gerum
0 siblings, 0 replies; 10+ messages in thread
From: Philippe Gerum @ 2025-04-10 9:45 UTC (permalink / raw)
To: Richard Weinberger; +Cc: Nikolaus Funk, xenomai, Jan Kiszka, Richard Weinberger
Hi Richard,
Richard Weinberger <richard@sigma-star.at> writes:
> On Dienstag, 8. April 2025 19:32 Jan Kiszka wrote:
>> > real-time. A notable example is a page fault, determining whether
>> > SIGSEGV is appropriate requires deep traversal into the memory
>> > management code.
>>
>> ...on arm and arm64. It worked fairly well for x86. This is indeed a
>> very prominent exception that people may expect behind this feature. And
>> it is also a use case we have with our (x86-only) deployment.
>
> True that.
> I think the set of supported exceptions should be architecture specific
> anyways. And we need to state that it is best effort.
>
>>
>> >
>> > Patches 1, 2, 3, and 4 implement the Xenomai-side changes for this
>> > feature. Dovetail will receive a separate patch set. Patches 5 and 6
>> > introduce tests.
>> >
>> > It is important to note that this is not a fully-fledged signal
>> > implementation. The only supported use case is delivering exceptions
>> > as signals to the affected thread.
>> > There is no support for sending signals or handling block/ignore masks.
>> > The only user visible API so far is cobalt_rt_signal().
>> > It takes a signal number (SIGILL or SIGFPE so far) and a handler
>> > function with the signature fn(int, siginfo_t *, void *).
>>
>> Did you intentionally left out the oldact parameter of sigaction?
>
> Not really. Adding this should be trivial.
> Maybe my subconsciousness tried to make it less look like POSIX
> real time signals. ;-)
>
>>
>> >
>> > TODO:
>> > - Better naming, IMHO "signal" is the wrong term and will confuse users.
>> > Especially since POSIX real-time signals are something different.
>> > Maybe "umex" for "user mode exception handling"?
>>
>> Just "exception" might be enough and clearer. OTOH, we are reusing a lot
>> of sigaction and siginfo...
>
> That's the problem. It kinda looks like signals but isn't.
>
Indeed. This rather looks like the handling side of the full exception
offloading path to me. That was the point of introducing the
mark_cond_trap_{entry, exit}() helpers. As you already know, when
notified of a trap, the companion core may decide _not_ to downgrade the
caller in-band, causing the regular low-level exception handlers to
assume that no more fix up is required.
>>
>> > - Document new APIs
>> > - Improve tests
>> > - Carefully select more exceptions
>>
>> Yeah, that is the challenge.
>>
>> And:
>>
>> - align with EVL / Xenomai 4 to ensure compatible features
>
> Agreed.
> The dovetail side is rather small. We could also integrate the signal frame
> helper functions into Xenomai.
>
I may be stating the obvious, but with hindsight, there is a basic
trade-off we have to do for fully offloading the exception handling over
the oob stage, based on the past experience with dealing with the
arch-specific code in Xenomai 3 + I-pipe:
- the more we ask the companion core (i.e. cobalt / evl) to implement
processor and/or standard abi-specific bits, the more we risk nasty
bugs over time. Typically, maintaining a duplicate fpu and context
switching code into the cobalt core during the I-pipe years has been
an excruciating nightmare, compared to the current state with Dovetail
which oob-enables the upstream code instead, presenting a complete
task switching service to the core. This can be extended to
implementing any duplicate/simplified version of an upstream routine
on the regular kernel side for oob-specific use (for that reason, I'm
not fond of the idea of copy&pasting in part the sigframe setup
code). IOW, a plain and obvious conflict with some upstream change in
a well-thought section of code shared between in-band and oob contexts
is usually way safer than an oob-specific code mimicking (portions of)
the in-band implementation living in parallel, since critical changes
in the latter might go unnoticed.
- but, introducing oob-awareness in some in-band code is obviously more
prone to merge conflicts, which might be another form of nightmare
when the latter is a moving target on the upstream side, when it comes
to tracking the kernel development tip.
To best decide, I agree with Jan that first and foremost, we need to
agree on an explicit feature set regarding exception offload to the
companion core including arch-specific issues/restrictions if any, so
that we may evolve the Dovetail implementation in the right direction in
this area. IIRC, we started a discussion on this list a couple of years
ago about this, for x86 at least.
--
Philippe.
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2025-04-10 9:45 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-04-08 12:28 [RFC PATCH 0/6] Xenomai: Real-time Exception Handling Nikolaus Funk
2025-04-08 12:28 ` [PATCH 1/6] cobalt/x86: Add architecture specific signal code Nikolaus Funk
2025-04-08 12:28 ` [PATCH 2/6] cobalt/arm64: " Nikolaus Funk
2025-04-08 12:28 ` [PATCH 3/6] cobalt/arm: " Nikolaus Funk
2025-04-08 12:28 ` [PATCH 4/6] cobalt: Add signal core code Nikolaus Funk
2025-04-08 12:28 ` [PATCH 5/6] testsuite: smokey: Add testcases for signals Nikolaus Funk
2025-04-08 12:28 ` [PATCH 6/6] utils: Add rt_signal_hist Nikolaus Funk
2025-04-08 17:32 ` [RFC PATCH 0/6] Xenomai: Real-time Exception Handling Jan Kiszka
2025-04-08 18:39 ` Richard Weinberger
2025-04-10 9:45 ` Philippe Gerum
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.