0

割り当てのためにシェル パイプの複製に取り組んでいます。パイプラインはすべて機能していましたが (それ以降、パイプライン コードを変更していないため、機能することがわかっています)、パイプラインのあるステップで実行に失敗した場合は、パイプラインを終了する必要がありました。そのコードを実装しているある時点で、パイプラインが予期しない動作を示し始めました。

長さ 2 のパイプラインは正しく機能します。長さが 2 を超えるパイプラインは、次のように失敗します。

  1. パイプラインの最初のコマンドが実行されます
  2. その直後 (多くの場合、最初のコマンドの実行が終了する前) に、パイプラインの最後のコマンドが終了します。
  3. 2 番目のコマンドがハングし、明らかに最初のコマンドから入力を受け取っていません。

以下は、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 番目の関数の終了ステータスが -2 であることが示されています。これは、もちろん、プログラムで存在ステータスを設定していないことを意味します。パイプラインは、これらのプログラムが実行されるのをまったく待っていないようです。

すなわち

入力 "ls | grep パイプ | 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
4

2 に答える 2

1

マクロを使用して、exit()返された値からプロセスを介して渡されたステータスを抽出します。waitpid()WEXITSTATUS()

の失敗のテストwaitpid()も間違っています。waitpid() return -1 on failure and in this case seterrno , which then would make sense to be interpreted by a call toperror()`.

perror()の値を読み取りますerrno。したがって、呼び出しは、 が設定されていることがわかっているperror()場合にのみ意味があります。これは、以下に示すように、コードの変更で I remove を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
      }
    }
  }
  ...
于 2013-05-13T16:07:03.560 に答える
0

それらは表面的なエラーに過ぎなかったため、waitpid の問題を見つけようとしたすべての人に謝罪します。実際のエラーパイプ コードにあり、途中で壊してしまったようです。

于 2013-05-13T17:43:24.050 に答える