Search code examples
clinuxunixsystemwait

Return value of waitpid


I am using waitpid(2) to check and mark the status of my processes of my job control program. I am using the WUNTRACED option, to catch useful signal like SIGTSTP in a job control program.

The problem is, when CTRL-Z (SIGTSTP) my program, the PID returned by waitpid(2) is correct (>0), but when killing it with a CTRL-C (SIGINT), the PID returned is -1. How is that ? How can I mark the status of my process then ? Since it return an invalid PID and set errno to ECHILD.

#include <sys/types.h>
#include <stdbool.h>
#include <termios.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>

int     main(void)
{
    pid_t   pid;
    pid_t   ret;
    int     stat_loc;

    if ((!(pid = fork())))
    {
        execve("/bin/ls", (char *const []){"ls", "-Rl", "/", NULL}, NULL);
    }
    else if (pid > 0)
    {
        signal(SIGINT, SIG_IGN);
        signal(SIGQUIT, SIG_IGN);
        signal(SIGTSTP, SIG_IGN);
        signal(SIGTTIN, SIG_IGN);
        signal(SIGTTOU, SIG_IGN);
        signal(SIGCHLD, SIG_IGN);
        ret = waitpid(-1, &stat_loc, WUNTRACED);
        printf("\nwaitpid returned %d\n", ret);
    }
    return (0);
}

EDIT: Problem solved, see the trick with SIGCHLD when you ignore it.


Solution

  • You're ignoring SIGCHLD:

    signal(SIGCHLD, SIG_IGN);
    

    Per POSIX:

    Status information for a process shall be generated (made available to the parent process) when the process stops, continues, or terminates except in the following case:

    • If the parent process sets the action for the SIGCHLD signal to SIG_IGN, or if the parent sets the SA_NOCLDWAIT flag for the SIGCHLD signal action, process termination shall not generate new status information but shall cause any existing status information for the process to be discarded.

    If you want to wait() on a child process, you can't ignore SIGCHLD.