[libc-commits] [libc] da99ce2 - [libc] Implement SA_NODEFER and SA_RESETHAND signal flags (#209429)
via libc-commits
libc-commits at lists.llvm.org
Tue Jul 14 04:23:04 PDT 2026
Author: Jeff Bailey
Date: 2026-07-14T12:23:00+01:00
New Revision: da99ce2fe0f4a185ceb02c9a650ba5efdb208612
URL: https://github.com/llvm/llvm-project/commit/da99ce2fe0f4a185ceb02c9a650ba5efdb208612
DIFF: https://github.com/llvm/llvm-project/commit/da99ce2fe0f4a185ceb02c9a650ba5efdb208612.diff
LOG: [libc] Implement SA_NODEFER and SA_RESETHAND signal flags (#209429)
Defined SA_NODEFER and SA_RESETHAND in Linux signal-macros.h.
Added unit tests in sigaction_test.cpp to verify the behavior of the new
flags. Also added a test case for SA_SIGINFO.
Assisted-by: Automated tooling, human reviewed.
Added:
Modified:
libc/include/llvm-libc-macros/linux/signal-macros.h
libc/test/src/signal/sigaction_test.cpp
Removed:
################################################################################
diff --git a/libc/include/llvm-libc-macros/linux/signal-macros.h b/libc/include/llvm-libc-macros/linux/signal-macros.h
index e7f268df87cba..b74d81683ac5e 100644
--- a/libc/include/llvm-libc-macros/linux/signal-macros.h
+++ b/libc/include/llvm-libc-macros/linux/signal-macros.h
@@ -73,6 +73,8 @@
#define SA_RESTART 0x10000000
#define SA_RESTORER 0x04000000
#define SA_ONSTACK 0x08000000
+#define SA_NODEFER 0x40000000
+#define SA_RESETHAND 0x80000000
// Signal stack flags
#define SS_ONSTACK 0x1
diff --git a/libc/test/src/signal/sigaction_test.cpp b/libc/test/src/signal/sigaction_test.cpp
index a12d7989586fe..c26cc4927e70f 100644
--- a/libc/test/src/signal/sigaction_test.cpp
+++ b/libc/test/src/signal/sigaction_test.cpp
@@ -63,3 +63,108 @@ TEST(LlvmLibcSigaction, Ignore) {
EXPECT_EXITS([] { LIBC_NAMESPACE::raise(SIGUSR1); }, 0);
}
+
+struct ResethandTest {
+ inline static int counter = 0;
+ static void handler(int) { counter++; }
+};
+
+// Verify that SA_RESETHAND resets the signal handler to SIG_DFL after one
+// execution.
+TEST(LlvmLibcSigaction, Resethand) {
+ ResethandTest::counter = 0;
+ struct sigaction action;
+ EXPECT_THAT(LIBC_NAMESPACE::sigaction(SIGUSR1, nullptr, &action), Succeeds());
+ action.sa_handler = ResethandTest::handler;
+ action.sa_flags = SA_RESETHAND;
+ EXPECT_THAT(LIBC_NAMESPACE::sigaction(SIGUSR1, &action, nullptr), Succeeds());
+
+ LIBC_NAMESPACE::raise(SIGUSR1);
+ EXPECT_EQ(ResethandTest::counter, 1);
+
+ // The handler should have been reset to SIG_DFL.
+ struct sigaction old_action;
+ EXPECT_THAT(LIBC_NAMESPACE::sigaction(SIGUSR1, nullptr, &old_action),
+ Succeeds());
+ EXPECT_EQ(old_action.sa_handler, SIG_DFL);
+}
+
+struct NodeferTest {
+ inline static int max_depth = 0;
+ inline static int depth = 0;
+ static void handler(int sig) {
+ depth++;
+ if (depth > max_depth)
+ max_depth = depth;
+ if (depth < 3)
+ LIBC_NAMESPACE::raise(sig);
+ depth--;
+ }
+};
+
+struct WithoutNodeferTest {
+ inline static int calls = 0;
+ inline static int max_depth = 0;
+ inline static int depth = 0;
+ static void handler(int sig) {
+ depth++;
+ calls++;
+ if (depth > max_depth)
+ max_depth = depth;
+ if (calls == 1)
+ LIBC_NAMESPACE::raise(sig);
+ depth--;
+ }
+};
+
+// Verify that SA_NODEFER allows recursive/nested signal delivery.
+TEST(LlvmLibcSigaction, Nodefer) {
+ NodeferTest::max_depth = 0;
+ NodeferTest::depth = 0;
+ struct sigaction action;
+ EXPECT_THAT(LIBC_NAMESPACE::sigaction(SIGUSR1, nullptr, &action), Succeeds());
+ action.sa_handler = NodeferTest::handler;
+ action.sa_flags = SA_NODEFER;
+ EXPECT_THAT(LIBC_NAMESPACE::sigaction(SIGUSR1, &action, nullptr), Succeeds());
+
+ LIBC_NAMESPACE::raise(SIGUSR1);
+ EXPECT_EQ(NodeferTest::max_depth, 3);
+
+ // Test without SA_NODEFER (default behavior: signal is blocked)
+ WithoutNodeferTest::max_depth = 0;
+ WithoutNodeferTest::depth = 0;
+ WithoutNodeferTest::calls = 0;
+ action.sa_handler = WithoutNodeferTest::handler;
+ action.sa_flags = 0;
+ EXPECT_THAT(LIBC_NAMESPACE::sigaction(SIGUSR1, &action, nullptr), Succeeds());
+
+ LIBC_NAMESPACE::raise(SIGUSR1);
+ EXPECT_EQ(WithoutNodeferTest::max_depth, 1);
+ EXPECT_EQ(WithoutNodeferTest::calls, 2);
+}
+
+struct SiginfoTest {
+ inline static bool received = false;
+ inline static int signo = 0;
+ static void handler(int, siginfo_t *info, void *) {
+ received = true;
+ if (!info)
+ return;
+ signo = info->si_signo;
+ }
+};
+
+// Verify that SA_SIGINFO invokes the sa_sigaction handler with siginfo_t.
+TEST(LlvmLibcSigaction, Siginfo) {
+ SiginfoTest::received = false;
+ SiginfoTest::signo = 0;
+ struct sigaction action;
+ EXPECT_THAT(LIBC_NAMESPACE::sigaction(SIGUSR1, nullptr, &action), Succeeds());
+ action.sa_sigaction = SiginfoTest::handler;
+ action.sa_flags = SA_SIGINFO;
+ EXPECT_THAT(LIBC_NAMESPACE::sigaction(SIGUSR1, &action, nullptr), Succeeds());
+
+ LIBC_NAMESPACE::raise(SIGUSR1);
+ EXPECT_TRUE(SiginfoTest::received);
+ EXPECT_EQ(SiginfoTest::signo, SIGUSR1);
+}
More information about the libc-commits
mailing list