From cf390d6a524a58982827ca556acabd2503e9fb44 Mon Sep 17 00:00:00 2001
From: 4lDO2 <4lDO2@protonmail.com>
Date: Thu, 4 Jul 2024 11:24:23 +0200
Subject: [PATCH] Add SIGCHLD test.

---
 tests/Makefile  |   1 +
 tests/sigchld.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 106 insertions(+)
 create mode 100644 tests/sigchld.c

diff --git a/tests/Makefile b/tests/Makefile
index 46690fd8..bb3ab909 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -30,6 +30,7 @@ EXPECT_NAMES=\
 	select \
 	setjmp \
 	sigaction \
+	sigchld \
 	signal \
 	stdio/all \
 	stdio/buffer \
diff --git a/tests/sigchld.c b/tests/sigchld.c
new file mode 100644
index 00000000..5e8a9ce2
--- /dev/null
+++ b/tests/sigchld.c
@@ -0,0 +1,105 @@
+#include <assert.h>
+#include <errno.h>
+#include <signal.h>
+#include <sched.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "test_helpers.h"
+
+volatile sig_atomic_t atomic = 0;
+volatile sig_atomic_t atomic2 = 0;
+
+void action(int sig, siginfo_t *info, void *context) {
+    (void)context;
+
+    assert(sig == SIGCHLD);
+    assert(info != NULL);
+    atomic += 1;
+}
+void handler(int sig) {
+    assert(sig == SIGPIPE);
+    atomic2 += 1;
+}
+
+int main(void) {
+    int child = fork();
+    ERROR_IF(fork, child, == -1);
+
+    int fds[2];
+    int status = pipe(fds);
+    ERROR_IF(pipe, status, == -1);
+
+    struct sigaction sa;
+    sigemptyset(&sa.sa_mask);
+    sa.sa_flags = 0;
+    sa.sa_sigaction = action;
+    status = sigaction(SIGCHLD, &sa, NULL);
+    ERROR_IF(sigaction, status, == -1);
+
+    sa.sa_handler = handler;
+    status = sigaction(SIGPIPE, &sa, NULL);
+    ERROR_IF(sigaction, status, == -1);
+
+    if (child == 0) {
+        status = close(fds[1]);
+        ERROR_IF(close, status, == -1);
+
+        char buf[1];
+        status = read(fds[0], buf, 1);
+        ERROR_IF(read, status, == -1);
+        puts("Child exiting.");
+        return EXIT_SUCCESS;
+    } else {
+        int waitpid_stat;
+
+        close(fds[0]);
+        ERROR_IF(close, status, == -1);
+
+        puts("Sending SIGSTOP...");
+        status = kill(child, SIGSTOP);
+        ERROR_IF(kill, status, == -1);
+
+        while (atomic == 0) {
+            status = sched_yield();
+            ERROR_IF(sched_yield, status, == -1);
+        }
+        puts("First handler ran, checking status.");
+
+        status = waitpid(child, &waitpid_stat, WUNTRACED);
+        ERROR_IF(waitpid, status, == -1);
+        assert(WIFSTOPPED(waitpid_stat));
+        assert(WSTOPSIG(waitpid_stat) == SIGSTOP);
+        puts("Correct, sending SIGCONT...");
+
+        status = kill(child, SIGCONT);
+        ERROR_IF(kill, status, == -1);
+
+        while (atomic == 1) {
+            status = sched_yield();
+            ERROR_IF(sched_yield, status, == -1);
+        }
+        puts("Second handler ran, checking status.");
+
+        status = waitpid(child, &waitpid_stat, 0);
+        ERROR_IF(waitpid, status, == -1);
+        assert(WIFEXITED(waitpid_stat));
+        assert(WEXITSTATUS(waitpid_stat) == 0);
+        puts("Child exited.");
+
+        puts("Writing to (broken) pipe.");
+        status = write(fds[1], "C", 1);
+        ERROR_IF(write, status, != -1);
+        assert(errno == EPIPE);
+
+        while (atomic2 == 0) {
+            status = sched_yield();
+            ERROR_IF(sched_yield, status, == -1);
+        }
+        puts("SIGSTOP handler successfully executed.");
+        return EXIT_SUCCESS;
+    }
+}
-- 
GitLab