2

When I receive a SIGCHLD blocking system calls like read doesn't return (with EINTR). If I get another signal they do.

It doesn't matter, whether the signal handler is set to a handler or to SIG_DFL. SA_RESTART isn't set, explicitly unsetting it with siginterrupt (SIGCHLD, TRUE) doesn't do anything.

Why is there special behaviour for SIGCHLD?
How can I configure, that syscalls should be interrupted by SIGCHILD?

2 Answers 2

1

I could not reproduce the behavior with this test program on Linux (6.11.10-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.11.10-1 (2024-11-23)):

#include <signal.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>

static sig_atomic_t child_caught = 0;

static void child_handler(int sig)
{
    child_caught++;
}

int main(void)
{
    int pipefd[2];
    int err;
    static const struct sigaction chld_action = {
        .sa_handler = child_handler,
    };
    pid_t child_pid;

    err = pipe(pipefd);
    if (err == -1) {
        perror("pipe");
        exit(EXIT_FAILURE);
    }

    err = sigaction(SIGCHLD, &chld_action, NULL);
    if (err == -1) {
        perror("sigaction");
        exit(EXIT_FAILURE);
    }

    child_pid = fork();
    if (child_pid == -1) {
        perror("fork");
        exit(EXIT_FAILURE);
    }

    if (child_pid == 0) {
        /* child */
        sleep(2);
        exit(EXIT_SUCCESS);
    } else {
        char buf[100];
        ssize_t rret;

        do {
            rret = read(pipefd[0], buf, sizeof(buf));
            if (rret == -1) {
                perror("read");
            } else {
                printf("read returned %zd\n", rret);
            }
        } while (rret > 0);
        printf("child_caught: %d\n", (int)child_caught);
        exit(rret ? EXIT_FAILURE : EXIT_SUCCESS);
    }
}

After 2 seconds, the program produced the following output, indicating that a SIGCHLD signal was caught and read failed with error EINTR ("Interrupted system call"):

read: Interrupted system call
child_caught: 1
Sign up to request clarification or add additional context in comments.

Comments

0

As Ian Abbott showed, system calls do in fact get interrupted by SIGCHLD.

However the system call I wanted to interrupt wasn't in the main thread, but system calls seam to be only interrupted in the thread, that receives the signal. Blocking the signal in the main thread fixed the problem:

sigset_t signal_set;
sigemptyset(&signal_set);
sigaddset(&signal_set, SIGCHLD);
sigprocmask(SIG_BLOCK, &signal_set, NULL);

What makes SIGCHLD special is, that when the handler is set to SIG_DFL, it is actually ignored, so there must be signal handler, even if it doesn't do anything:

static void noop_handler (int signal) {
    return;
}

struct sigaction handler = {0};
handler.sa_handler = noop_handler;
sigaction (SIGCHLD, &handler, NULL))

That maked me think, that SIGCHLD doesn't work, but combining both it does.

However, I wonder, if there is a different way to achieve that signal disposition, then specifying ǹoop_handler.

7 Comments

For multi-threaded applications, I think it is better to replace asynchronous signal handlers with synchronous signal handling thread(s).
Yes, but isn't that what I am doing though? The signal handler is just a no-op and only used to resume from a blocking call. Or do you mean something else?
I guess it's OK as long as the signal handler doesn't need to do anything fancy.
If you know a better way, please elaborate.
To elaborate, I would move the blocking into a poll() call and include some other file descriptor in the poll read set that will become readable when some exceptional event has occurred, e.g. include the file descriptor of the "read" end of a pipe in the poll read set, and arrange for the "write" end of the pipe to either be written to or closed when some exceptional event has occurred, either of which would make the "read" end of the pipe readable (if the "write" end of the pipe is closed, the EOF condition on the "read" end is readable). This only works for I/O though, not sleep().
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.