diff --git a/tests/Makefile b/tests/Makefile index 46690fd8f2904e30a8a8a18a7bf15b859a7665a6..bb3ab9094634c50fc1239a60697b1aae6349e12a 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 0000000000000000000000000000000000000000..5e8a9ce2dfabe1f21a4a148ead62acf9f2c680da --- /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; + } +}