2017-07-01 11 views
0

私は対話型プログラムの周りにラッパーを作ろうとしています。このため私はpipe,dup2pollの組み合わせを使用します。すべてが子どもが終わるまでうまくいくようです。このステップでは、親プロセスはstdinを失うように見えますが、なぜそれが理解できないのでしょうか。コンソール入力に親の任意のアクセスに影響を与えるべきではないと思われるので、ここでは子供は、dup2経由で暗黙のうちに元のstdin閉じ子供が死亡した後、親プロセスがコンソール入力を失うのを防ぐには?

#include <unistd.h> 
#include <sys/types.h> 
#include <stdlib.h> 
#include <stdio.h> 
#include <poll.h> 
#include <fcntl.h> 
#include <signal.h> 

#include <vector> 
#include <string> 
#include <iostream> 

struct SystemFunctionFailure 
{ 
    std::string what; 
    SystemFunctionFailure(std::string const& what) : what(what) {} 
}; 

template<typename T,size_t N> constexpr size_t countof(const T(&)[N]) { return N; } 

void readAndPrint(std::string const& what, int fd) 
{ 
    std::cerr << "Reading "+what+"\n"; 
    std::vector<char> buffer(1024); 
    const auto bytesRead=read(fd,buffer.data(),buffer.size()); 
    if(bytesRead==-1) 
    { 
     if(errno!=EAGAIN) 
      throw SystemFunctionFailure("read "+what); 
    } 
    else if(bytesRead==0) 
    { 
     std::cerr << "EOF reached on "+what+"\n"; 
     exit(0); 
    } 
    else 
     std::cerr << "CONTENTS OF "+what+": "+std::string(buffer.data(),buffer.size())+"\n"; 
} 

int main() 
{ 
    try 
    { 
     int pipeChildOut[2]; 
     if(pipe(pipeChildOut)==-1) throw SystemFunctionFailure("pipe for child stdout"); 

     int pipeChildErr[2]; 
     if(pipe(pipeChildErr)==-1) throw SystemFunctionFailure("pipe for child stderr"); 

     int pipeChildIn[2]; 
     if(pipe(pipeChildIn)==-1) throw SystemFunctionFailure("pipe for child stdin"); 

     const auto child=fork(); 
     if(child==-1) throw SystemFunctionFailure("fork"); 

     if(child) 
     { 
      dup2(pipeChildOut[1],STDOUT_FILENO); 
      close(pipeChildOut[0]); 
      dup2(pipeChildErr[1],STDERR_FILENO); 
      close(pipeChildErr[0]); 
      dup2(pipeChildIn[0],STDIN_FILENO); 
      close(pipeChildIn[1]); 
      execlp("sh","sh","-c","sleep 1; echo Test ; sleep 1; echo Child is exiting... >&2",nullptr); 
      throw SystemFunctionFailure("execlp returned"); 
     } 
     else 
     { 
      const int childStdErr=pipeChildErr[0]; 
      const int childStdOut=pipeChildOut[0]; 
      dup2(pipeChildIn[1],STDOUT_FILENO); 
      fcntl(childStdErr,F_SETFL,O_NONBLOCK); 
      fcntl(childStdOut,F_SETFL,O_NONBLOCK); 
      fcntl(STDIN_FILENO,F_SETFL,O_NONBLOCK); 

      while(true) 
      { 
       std::cerr << "New iteration of IO loop\n"; 
       pollfd pollfds[]={ // making the indices coincide with .._FILENO 
            {STDIN_FILENO,POLLIN}, 
            {childStdOut,POLLIN}, 
            {childStdErr,POLLIN}, 
           }; 
       if(poll(pollfds,countof(pollfds),{-1})==-1) 
        throw SystemFunctionFailure("poll"); 
       std::cerr << "poll returned\n"; 

       for(unsigned i=0;i<countof(pollfds);++i) 
        std::cerr <<" pollfds["<<i<<"].revents: " << pollfds[i].revents << "\n"; 

       if(pollfds[ STDIN_FILENO].revents&POLLIN) readAndPrint("stdin" ,pollfds[ STDIN_FILENO].fd); 
       if(pollfds[STDOUT_FILENO].revents&POLLIN) readAndPrint("stdout",pollfds[STDOUT_FILENO].fd); 
       if(pollfds[STDERR_FILENO].revents&POLLIN) readAndPrint("stderr",pollfds[STDERR_FILENO].fd); 
      } 
     } 
    } 
    catch(SystemFunctionFailure& ex) 
    { 
     perror(ex.what.c_str()); 
     exit(EXIT_FAILURE); 
    } 
} 

は、ここでは、コードです。しかし何らかの理由でここに私が出力として得られるものがあります:

Ie.シェルのプロンプトが表示されるので、親はもうフォアグラウンドにいません。私は、数秒待ってから文字を入力する場合は、この後、私はこの出力を得る:

poll returned 
pollfds[0].revents: 1 
pollfds[1].revents: 0 
pollfds[2].revents: 0 
Reading stdin 
read stdin: Input/output error 

私は、少なくとも子供が死んだ後、親プロセスはそのコンソール入力へのアクセスを維持したいのですが。 an answer to another questionを読んだ後、私の問題は関連していると思いますが、その答えは私の質問には答えません。

答えて

1

if(child)if(child == 0)である必要があります。成功したhttps://linux.die.net/man/2/fork

から

は、子プロセスのPIDは と0子で返され、親に返されます。失敗した場合は、 親に-1が返され、子プロセスは作成されず、errnoが適切に設定されます。

+0

あなたはそうです。それは愚かな間違いでした。 – Ruslan

関連する問題