NewGuy
NewGuy

Reputation: 89

How would I check for child process changing state but not terminating?

I'm using waitpid to get status code returned by the child when it changes state. I'm using:

if (WIFEXITED(code)){
    if (WEXITSTATUS(code)==0){
        //worked correctly
    }
    else{
        //failed, throw error
    }
}
else{
..
}

In the bottom part, I want to check for whether the child changed state without terminating and wait for it to terminate using a loop. How can I do so?

Upvotes: 1

Views: 2184

Answers (1)

Wintermute
Wintermute

Reputation: 44043

Assuming you don't ptrace the child process, you have to wait for it with the WUNTRACED and WCONTINUED flags:

 waitpid(pid, &code, WUNTRACED | WCONTINUED);

If you do ptrace it, WUNTRACED is unnecessary, but since ptrace is a different kettle of fish altogether, I'll not go into it in detail.

Then, you can check what happened like so:

if (WIFEXITED(code)) {
  // process ended normally with exit status WEXITSTATUS(code)
} else if(WIFSIGNALLED(code)) {
  // process was terminated by signal WTERMSIG(code)
} else if(WIFSTOPPED(code)) {
  // child was stopped by signal WSTOPSIG(code)
} else if(WIFCONTINUED(code)) {
  // child was continued
}

To get a feeling for the way this works, you can play around with this piece of code:

#include <stddef.h>
#include <stdio.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

int main() {
  pid_t pid;

  pid = fork();

  if(pid == -1) {
    fputs("fork failed\n", stderr);
  } else if(pid == 0) {
    int i;

    for(i = 0; i < 100; ++i) {
      usleep(1000000);
      puts("child");
    }
  } else {
    int status;

    printf("%d\n", pid);

    do {
      waitpid(pid, &status, WUNTRACED | WCONTINUED);
      printf("exited:    %d status: %d\n"
             "signalled: %d signal: %d\n"
             "stopped:   %d signal: %d\n"
             "continued: %d\n",
             WIFEXITED(status),
             WEXITSTATUS(status),
             WIFSIGNALED(status),
             WTERMSIG(status),
             WIFSTOPPED(status),
             WSTOPSIG(status),
             WIFCONTINUED(status));
    } while(!WIFEXITED(status) && !WIFSIGNALED(status));
  }

  return 0;
}

This will fork, the parent process will print the process ID of the child process, and when you send the child process signals, the parent will print the status properties it gets from waitpid (not all of them will make sense, naturally; if the process is stopped, WTERMSIG does not return anything meaningful). Here's my example output from a session in which I sent the child process SIGSTOP, SIGCONT, and SIGTERM:

38167
child
child
child
child
exited:    0 status: 19
signalled: 0 signal: 127
stopped:   1 signal: 19
continued: 0
exited:    0 status: 255
signalled: 0 signal: 127
stopped:   0 signal: 255
continued: 1
child
child
child
exited:    0 status: 0
signalled: 1 signal: 15
stopped:   0 signal: 0
continued: 0

Upvotes: 1

Related Questions