Search code examples
clinuxmultithreadingsignals

waitpid stops waiting after signal is sent


I am currently working on a C project for university. Among other things I should signal the parent process using SIGUSR1. The problem I'm facing at the moment is that I also need to wait for the child process to terminate so I can safely shut down everything in the end (removing shared Memory etc.).

At the moment I am using sigaction() to respond to the signal and waitpid() to wait for the child to terminate (that was the plan anyways ^^). But when I signal the parent using kill(), waitpid() stops waiting and runs the remainder of the parent even though the child is still running.

I feel like I'm missing something obvious but I can't figure it out.

Any help is greatly appreciated, stay safe

Tim

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <unistd.h>

void handle_sigusr1(int sig) {
  printf("Recieved signal %i.\n", sig);
}

int main() {
  pid_t pid;
  pid = fork();

  if (pid == -1) {
    perror("fork:");
    return EXIT_FAILURE;
  }

  else if (pid == 0) {
    printf("Hello from the child.\n");
    kill(getppid(), SIGUSR1);
    sleep(3);
    printf("Hello again from the child.\n");
    return EXIT_SUCCESS;
  }

  else {
    printf("Hello from the parent.\n");
    struct sigaction sa;
    sa.sa_handler = &handle_sigusr1;
    sigaction(SIGUSR1, &sa, NULL);
    int status;
    waitpid(pid, &status, 0);
    if (WIFEXITED(status))
      printf("Exit status: %i\n", WEXITSTATUS(status));
    printf("Finished waiting for child.\n");
    return EXIT_SUCCESS;
  }
}

Output:

Hello from the parent.
Hello from the child.
Recieved signal 10.
Exit status: 0
Finished waiting for child.
tim@schlepptop:signalTest$ Hello again from the child.

PS: WEXITSTATUS(status) is usually 0 but sometimes it's also something like 16 or 128.


Solution

  • Per POSIX waitpid() documentation:

    RETURN VALUE

    ... If wait() or waitpid() returns due to the delivery of a signal to the calling process, -1 shall be returned and errno set to [EINTR]. ...

    You need to check the return value:

    int status
    do
    {
        errno = 0;
        int rc = waitpid(pid, &status, 0);
        if ( rc != -1 )
        {
            break;
        }
    }
    while ( errno == EINTR );