私は対話型プログラムの周りにラッパーを作ろうとしています。このため私はpipe
,dup2
とpoll
の組み合わせを使用します。すべてが子どもが終わるまでうまくいくようです。このステップでは、親プロセスは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を読んだ後、私の問題は関連していると思いますが、その答えは私の質問には答えません。
あなたはそうです。それは愚かな間違いでした。 – Ruslan