3

I've created a rudimentary example of monitoring a child process and restarting it when it fails or exits. What is the preferred/more robust method of doing this? Is it good practice to continuously poll for a change in status? My understanding is that I should utilize something like SIGCHLDbut have been unable to find any good examples.

I'm an embedded C coder mainly and this is my first attempt at trying to understand fork().The purpose of this code will eventually be to monitor a call to another program using exec() and restart this program if and when it fails or finishes.

Edit: After comments from @cnicutar I have rewritten the example below in a way I think makes more sense in the hope that it is of use to somebody later. I would like the parent to monitor a child process whilst foing other things and make a new call to exec on a new fork when the child process fails/finishes. I want to try and use unix signals to achieve this

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

int main(int argc, char *argv[])
{
    pid_t cpid;
    int status;
    cpid = fork();
    for (;;)
    {
        switch (cpid)
        {
        case -1 : //Fork failure
            exit(EXIT_FAILURE);
            break;

        case 0 : //Child Process
            exec(some function);
            return 0; //exit child process
            break;

        default : //Parent process
            if (waitpid(-1, &status, WNOHANG) != 1) cpid = fork(); //restart 
            //Do parent stuff here...
            break;
        }
    }
}
CatsLoveJazz
  • 829
  • 1
  • 16
  • 35

1 Answers1

2

Adding a SIGCHLD handler won't buy you much since you already wait all the time and only do that - there's nothing else to "interrupt".

One thing I would suggest is a threshold such that the process doesn't die/start too often.

My understanding is that I should utilize something like SIGCHLD but have been unable to find any good examples

You use SIGCHLD to know when to wait. A typical SIGCHLD handler just does waitpid in a loop until no children are left. In your case you don't need that since your main code is a loop stopped on waitpid.


EDIT

You can find plenty of examples for SIGCHLD handling. One such example is How can I handle sigchld in C. In that code, after the while you can just fork:

while((pid = waitpid(-1, &status, WNOHANG)) > 0)
        ;

pid = fork();
switch (pid)
...

To reiterate, if you do this SIGCHLD will be called every time a child dies and after you properly wait for it you can just fork another. This only makes sense if the parent has better stuff to do in the meantime than to just block on waitpid.


Word to the wise. There are certain functions that must not be called from a signal handler lest you add difficult bugs to your program. Look up "async signal safe" functions: these and only these can be called from a signal handler. Some of the most common functions (like printf and malloc) cannot be called from a signal handler.

Community
  • 1
  • 1
cnicutar
  • 178,505
  • 25
  • 365
  • 392
  • Thanks, I suppose I realize now my question was not so much how to monitor/wait for the child process to end but what the best practices are for restarting it. My method seems of setting a flag seems to work but is there a native C, unix way to handle this? `if (alive == 0) cpid = fork(); alive = 1;` – CatsLoveJazz Mar 05 '14 at 09:31
  • @CatsLoveJazz I am not sure you really need the flag. The only way for the fork to be reached is for `waitpid` to unblock, which happens when the process dies or is killed by a signal. – cnicutar Mar 05 '14 at 10:49
  • Of course, sorry. What I meant was suppose the parent process was not waiting and only checking the child process with an if once per the main loop. How would this be handled without calling `fork` each time? – CatsLoveJazz Mar 05 '14 at 10:58
  • @CatsLoveJazz If I understand your question correctly, then yes, it is indeed possible to install a signal handler for `SIGCHLD` and `fork` from it. `fork` happens to be async-signal-safe so this should be pretty straightforward. – cnicutar Mar 05 '14 at 11:36
  • Thanks for the comments @cnicutar, I've rewritten the code example and restated my question in a (hopefully) cleaner and more concise way. – CatsLoveJazz Mar 05 '14 at 12:44
  • @CatsLoveJazz I am not sure about the way you modified the code. I think you can either keep the old version, just without `alive` or add a new version with only a `SIGCHLD` handler that forks. If you want me to I can write a skeleton for such a handler. – cnicutar Mar 05 '14 at 16:28
  • Its the SIGCHLD handler I don't know understand how to write or where its called. I hoped modifying the code made it easier to explain my issue. Thanks for the continuing help! – CatsLoveJazz Mar 05 '14 at 16:41
  • @CatsLoveJazz I added a link to an example and a few lines of advice. – cnicutar Mar 05 '14 at 16:48
  • Thank you, this is exactly what I was looking for but lacked the knowledge to know how to ask! – CatsLoveJazz Mar 05 '14 at 19:39