Skip to content
Snippets Groups Projects
Forked from redox-os / relibc
425 commits behind the upstream repository.
sigchld.c 2.84 KiB
#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 fds[2];
    int status = pipe(fds);
    ERROR_IF(pipe, status, == -1);

    int child = fork();
    ERROR_IF(fork, child, == -1);

    sigset_t set;
    sigemptyset(&set);
    status = sigprocmask(SIG_SETMASK, &set, NULL);
    ERROR_IF(sigprocmask, 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 = write(fds[1], "C", 1);
        ERROR_IF(write, status, == -1);

        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], "B", 1);
        assert(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;
    }
}