1

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?

NewGuy
  • 89
  • 1
  • 5
  • What do you mean by 'changes state'? `wait` etc will only notice exits. – abligh Jan 29 '15 at 07:57
  • If it changed state and the state change did not lead to it exiting, then it "changed state without terminating", so what is wrong with your `else`? – danielschemmel Jan 29 '15 at 07:59
  • @abligh It notices all state changes. From man page: " A state change is considered to be: the child terminated; the child was stopped by a signal; or the child was resumed by a signal." – NewGuy Jan 29 '15 at 08:00
  • Maybe threads would be sufficient? One thread can poll, the other can continuously loop for whatever else you need. – CinchBlue Jan 29 '15 at 08:41

1 Answers1

1

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
Wintermute
  • 42,983
  • 5
  • 77
  • 80