views:

48

answers:

2

I'm writing a pseudo shell program which creates a child from a parent process. The parent process waits for the child to finish before continuing. My forking code looks something like this:

if(fork()==0)
{
     execvp(cmd, args);
}
else
{
     int status = 0;
     wait(&status);
     printf("Child exited with status of %d\n", status);
}

But, I want to be able to parse the '&' operator, such that if a user enters it at the end of a command line, the parent won't wait for the child before prompting the user for another command. I added some code to handle this, but I wasn't exactly sure if it's working right. Would it look something like:

if(fork()==0)
{
    execvp(cmd, args);
}
else
{
    if(andOp = 1) //boolean to keep track of if '&' was encountered in parsing
    {
        shellFunc();   //main function to prompt user for a cmd line
    }
    int status = 0;
    wait(&status);
    printf("Child exited with status of %d\n", status);
}

Does this actually accomplish the concurrency achieved by the regular shell?

+2  A: 

Beware assignment instead of comparison.

Beware failing to execute a command - exit(1); after execvp().

I think I would use:

if (andOp == 0)
{
     int status;
     int corpse = wait(&status);
     printf("Child %d exited with status 0x%04X\n", corpse, status);
}

That is, I'd only wait if the '&' was missing.

However, with background children dying at random, you need to keep track of the background processes, and in particular, you need to loop on wait() until the child you just forked off dies. So you also need to trap that PID from the fork().

You might want to get fancy and use waitpid() after collecting the child you were waiting for, to clean up any other bodies, using the non-blocking option so that if there are no such children, it returns immediately. You'd still use it in a loop, so that if 6 background jobs all completed, you collect them all.

Alternatively again, you could consider ignoring 'death of child' (SIGCHLD) signals - and letting the system take care of them. However, a shell typically reports when one of the background jobs completes.

Jonathan Leffler
A: 

A couple of problems:

  • What if the exec fails?
    • You should kill the child
  • What if a signal happens in the parent?
    • wait will exit. You need to detect and re-wait.
  • Call the ShellFunc() recursively does not help as there is no real exit stratergy.
    • use int sigaction() to detect child failure on backgrounded tasks.
Martin York