0

I'm working on replicating shell pipes for an assignment. I had the pipeline all working (and have not since changed the pipeline code, so that is known to work), but still needed to terminate the pipeline in the event of an execution failure in some step of the pipeline. At some point while implementing that code, the pipeline started exhibiting unexpected behavior.

Pipelines of length two work correctly. Pipelines of length greater than two fail in the following way:

  1. The first command in the pipeline executes
  2. Immediately afterwards — often before the first command finishes executing — the final command in the pipeline terminates
  3. The second command will then hang, apparently having received no input from the first command.

Here is the section code that uses waitpid (sans debug code):

for (int i = 0 ; i < num_cmds ; i++) {
  if (waitpid(cmd_pids[i], &cmd_status[i], NULL) != cmd_pids[i]) {
     printf("Error waiting for command %s\n", cmds[i]);
     perror("Error");
  }
  if ((cmd_status[i] > 0) && (cmd_status[i-1] == 0)) {
     killPipeline(SIGINT); //Kill pipeline; something failed
  }
  fflush(logfp);

}

Now here's the crux of why I think the waitpid section is to blame: due to some odd control flow that the assignment demands, I have found it convenient to initialize the values of cmd_status to -2. The logging function prints the return statuses of the child processes to a log, and the file says the exit status of the second function is -2, which is of course means that it isn't setting the exist status on the program. It seems that the pipeline isn't waiting for these programs to execute at all.

i.e.

input "ls | grep pipe | wc"

output:

You entered : list of pipe commands  ls | grep pipe | wc
Creating process ls
Creating process grep pipe
Creating process wc
Waiting for command ls
      0       0       0 //wc received no input, but somehow an EOF
Command ls finished
Waiting for command grep
^C  //Terminate grep because it's waiting for input from a terminated process
Error waiting for command grep
Error: Interrupted system call
Command grep finished
Waiting for command wc
Command wc finished
C. Warren Dale
  • 184
  • 2
  • 11
  • I think in your second if statment, cmd_status[i-1] != 0 since 0 indicates that those processes have not yet finished (changed state). – KrisSodroski May 13 '13 at 16:09

2 Answers2

1

To extract the status passed to exit() via a process fro the value returned by waitpid() use the macro WEXITSTATUS().

Also the test for a failure of waitpid() is wrong. waitpid() return -1 on failure and in this case seterrno, which then would make sense to be interpreted by a call toperror()`.

perror() reads out the value of errno. So calling perror() make sense only if errno is known to have been set. This was was not the case in the call to perror("Error") I remove in my modification of your code, as shown below.

for (int i = 0 ; i < num_cmds ; i++) 
{
  int status = -1;
  int result = waitpid(cmd_pids[i], &status, NULL);
  if (-1 == result)
  {
    perror("waitpid()"); /* added call to perror() here as errno is know to have been set */
  }
  else
  { 
    if (result != cmd_pids[i]) 
    {
      fprintf(stderr, "Error waiting for command '%s'\n", cmds[i]);
      /* removed call to perror() here as errno had not been set here. As this however should
         log an error, I modded the code to printf to stderr, but stdout. */
    }
    else
    {
      cmd_status[i] = WEXITSTATUS(status);

      if ((cmd_status[i] > 0) && ((0 == i) || (cmd_status[i-1] == 0))) /* This mod keeps   
        the app from dereferencing cmd_status in case i == 0, as this would lead to 
        cmd_status[-1], which is undefined beaviour. */
      {
        killPipeline(SIGINT); //Kill pipeline; something failed
      }
    }
  }
  ...
alk
  • 69,737
  • 10
  • 105
  • 255
  • While I see that there are plenty of minor issues here, and I am grateful that you have pointed them out, none of these changes (I have implemented them) actually solve the curious behavior. – C. Warren Dale May 13 '13 at 17:13
  • Actually, I attempted to start from a previous commit and reimplement the pipeline changes to start afresh. Same behavior, so I can no longer guarantee that the pipeline code is correct. – C. Warren Dale May 13 '13 at 17:33
0

Apologies to everyone who attempted to find the any issues with waitpid, as they were only superficial errors. The actual error did lie in my pipe code, which I apparently wrecked along the way.

C. Warren Dale
  • 184
  • 2
  • 11