Waiting for a signal from another process using sigwait ()

Question:

I am trying to figure out processes and signals in Unix and the following problem came up.

main.c

int main(int argc, char** argv) {
  pid_t fork_pid = fork();
  if (fork_pid < 0) {
      exit(EXIT_FAILURE);
  }
  if (fork_pid == 0) {
      printf("Child will wait\n");
      sigset_t   set;
      int sig;
      sigemptyset(&set);                                                            
      sigaddset(&set, SIGUSR1);                                                                      
      sigwait(&set, &sig);
      printf("Child recive signal\n");
      exit(EXIT_SUCCESS);
  }
  if (fork_pid > 0) {
      // Do something before child
      kill(fork_pid,SIGUSR1);
      int res;
      wait(&res);
      printf("Child exit code: %d\n", res);
      // Do something after child
  }
}

At the first launch, everything worked well, but then everything broke.

The conclusion was this

Child exit code: 30

Remarkably, the SIGUSR1 constant on my machine is 30! I am more than sure that this is related, but there is clearly not enough knowledge to understand how to fix it.

Thanks in advance for your reply!

UPDATE:

It became clear that the child process might not be ready to receive a signal during a kill call. But how to fix it is still not clear.

Answer:

The status value contains not only the return code from exit() , but also the reason for termination in one variable, to separate one from the other there are macros WIFEXITED , WEXITSTATUS , etc., see the example below. In your case, the status did indeed contain the number of the interrupting signal.

If a signal comes to sigwait() , the handler function is not called (checked in Linux). But if the handler is not installed, the default reaction occurs, in this case the program termination. If you ignore the signal ( signal(SIGUSR1, SIG_IGN) ), sigwait is not interrupted by the signal. Therefore, the handler function is still needed, in addition, it is needed in case the signal sigwait() before the call to sigwait() .

You can use a pipe to wait for the parent process for the child to be ready.

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

volatile int sigcount;
void handler_count(int signal_num)
{
    sigcount++;
}
int main(int argc, char **argv)
{
    int pipefd[2];
    pipe(pipefd);
    pid_t fork_pid = fork();
    if (fork_pid < 0) {
        exit(EXIT_FAILURE);
    }
    if (fork_pid == 0) {
        printf("Child will wait\n");
        sigset_t set;
        int sig;
        signal(SIGUSR1, &handler_count);
        close(pipefd[0]);
        sigemptyset(&set);
        sigaddset(&set, SIGUSR1);
        write(pipefd[1], "", 1); // процесс готов к приёму сигнала
        close(pipefd[1]);
        sigwait(&set, &sig); // если заменить на  pause(); счётчик увеличивается
        printf("Child recived signal, sigcount=%d\n", sigcount);
        exit(EXIT_SUCCESS);
    }
    if (fork_pid > 0) {
        char c;
        close(pipefd[1]);
        read(pipefd[0], &c, 1); // ожидание готовности потомка
        close(pipefd[0]);
        kill(fork_pid, SIGUSR1);
        int status;
        if (wait(&status)<0) {
            perror("wait");
        } else if (WIFEXITED(status)) {
            printf("Child exited, status=%d\n", WEXITSTATUS(status));
        } else if (WIFSIGNALED(status)) {
            printf("Child killed by signal %d\n", WTERMSIG(status));
        } else if (WIFSTOPPED(status)) {
            printf("Child stopped by signal %d\n", WSTOPSIG(status));
        } else if (WIFCONTINUED(status)) {
            printf("Child continued\n");
        }
    }
}
Scroll to Top