I try to deal with the processes and signals in Unix and the following problem arose.

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 } } 

When you first started everything worked well, but then everything broke.

The conclusion was

 Child exit code: 30 

It is remarkable that the constant SIGUSR1 on my machine is 30! I am more than sure that it is connected, but there is clearly not enough knowledge to figure out how to fix it.

Thank you all in advance for the answer!

UPDATE:

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

  • one
    And no one guarantees that the parent process will kill after the child is ready to receive the signal. he may not be ready yet and kill him. need to use process synchronization tools. - Mike
  • @Mike I guessed it was true, but I still don’t know how to fix it. "Process synchronization tools" unfortunately does not tell me anything. More? - Mix74rus
  • средства синхронизации процессов : mutexes, semaphores, conditional variables ... that is all. - αλεχολυτ
  • @alexolut mutexes, semaphores are used when working with threads, not processes. - Yaroslav
  • @Yaroslav stackoverflow.com/a/9426906/3240681 - αλεχολυτ

2 answers 2

The status value contains not only the return code from exit() , but also the reason for the completion in one variable, to separate one from another, there are macros WIFEXITED , WEXITSTATUS , etc., see the example below. In your case, the status really contained the number of the interrupted signal.

If the signal arrives in sigwait() , the handler function is not called (tested in Linux). But if the handler is not installed, a default reaction occurs, in this case, the program is terminated. If you ignore the signal ( signal(SIGUSR1, SIG_IGN) ), the 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 sigwait() call.

A pipe can be used to wait for the parent to be ready for the child.

 #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"); } } } 

    To test signals, it is necessary to synchronize processes, one process must configure a signal handler, and another process must send a signal when the first program has installed an interrupt handler. In this case, it is better to make two programs.

    This is not a large program that installs a signal handler for a SIGUSR1 signal. You can send a SIGUSR1 signal with the command kill -s SIGUSR1 <pid>

     #include <stdio.h> #include <unistd.h> #include <string.h> #include <signal.h> static volatile sig_atomic_t count = 0; void handler_count(int signal_num) { count++; } static int set_signals(void) { struct sigaction act; sigset_t set; memset(&act, 0x0, sizeof(act)); if(sigfillset(&set) < 0){ printf("sigfillset failed\n"); return 0; } act.sa_handler = handler_count; if(sigaction(SIGUSR1, &act, NULL) < 0){ printf("sigaction failed SIGALRM\n"); return 0; } if(sigemptyset(&set) < 0){ printf("sigemptyset failed\n"); return 0; } return 1; } int main(int argc,char * argv[]) { if(set_signals() == 0) return 0; for(;;){ pause(); if(count == 5){ break; } printf("count :> %d\n",count); } return 0; }