waitpid(pid,status,options)并不总是设置状态

时间:2013-05-13 16:03:19

标签: c system-calls waitpid

我正在为作业复制shell管道。我让管道全部工作(并且之后没有更改管道代码,因此已知可以工作),但是在管道的某个步骤中执行失败的情况下仍然需要终止管道。在实现该代码的某个时刻,管道开始出现意外行为。

长度为2的管道正常工作。 长度大于2的管道以下列方式失败:

  1. 管道中的第一个命令执行
  2. 之后 - 通常在第一个命令完成执行之前 - 管道中的 final 命令终止
  3. 第二个命令将挂起,显然没有收到第一个命令的输入。
  4. 以下是使用waitpid(无调试代码)的部分代码:

    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);
    

    }

    现在这里是我认为waitpid部分应该受到指责的关键所在:由于分配所需的一些奇怪的控制流,我发现将cmd_status的值初始化为-2很方便。日志功能将子进程的返回状态打印到日志,文件说第二个函数的退出状态为-2,这当然意味着它没有在程序上设置存在状态。似乎管道根本没有等待这些程序执行。

    输入“ls | grep pipe | wc”

    输出:

    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
    

2 个答案:

答案 0 :(得分:1)

要通过exit()返回的值的处理提取传递给waitpid()的状态,请使用宏WEXITSTATUS()

waitpid()失败的测试也是错误的。 waitpid() return -1 on failure and in this case set的errno , which then would make sense to be interpreted by a call to PERROR()`。

perror()读出errno的值。因此,只有知道已设置perror()时,调用errno才有意义。在我修改代码时删除的perror("Error")调用中的情况并非如此,如下所示。

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
      }
    }
  }
  ...

答案 1 :(得分:0)

向所有试图找到waitpid问题的人致歉,因为它们只是表面错误。我的管道代码中的实际错误确实存在,我显然在此过程中失败了。