everything is ok, when pipes are non blocking on parent's side and blocking on client's side, and select is not used (not necessary for non blocking IO)
This commit is contained in:
88
mrw/exec.cpp
88
mrw/exec.cpp
@@ -9,6 +9,9 @@
|
||||
@license LGPL, see file <a href="license.html">COPYING</a>
|
||||
|
||||
$Log$
|
||||
Revision 1.8 2004/12/18 21:00:09 marc
|
||||
everything is ok, when pipes are non blocking on parent's side and blocking on client's side, and select is not used (not necessary for non blocking IO)
|
||||
|
||||
Revision 1.7 2004/12/17 17:38:57 marc
|
||||
it works perfectly with blocking pipes and buffer size of 1
|
||||
|
||||
@@ -36,12 +39,10 @@
|
||||
#include <mrw/unistd.hpp>
|
||||
#include <mrw/exception.hpp>
|
||||
#include <mrw/stdext.hpp> // max
|
||||
#include <sys/wait.h> // waitpid
|
||||
#include <unistd.h> // fork, exec
|
||||
#include <sys/wait.h> // waitpid#include <unistd.h> // fork, exec
|
||||
#include <string.h> // memcpy
|
||||
#include <assert.h> // assert
|
||||
|
||||
#include <iostream>
|
||||
mrw::ExecutionFailedExc::ExecutionFailedExc(const std::string& w,
|
||||
const std::string& c)
|
||||
throw(std::bad_exception):
|
||||
@@ -133,7 +134,7 @@ mrw::Exec& mrw::Exec::execute(bool exc) throw(std::exception) {
|
||||
program. */
|
||||
_success = false;
|
||||
_res = _err = "";
|
||||
mrw::Pipe stdOut(true), stdErr(true);
|
||||
mrw::Pipe stdOut(mrw::Pipe::block_output), stdErr(mrw::Pipe::block_output);
|
||||
if (!stdOut || !stdErr)
|
||||
throw mrw::ExecutionFailedExc("cannot create pipe", *_cmd);
|
||||
pid_t pid(fork());
|
||||
@@ -144,37 +145,26 @@ mrw::Exec& mrw::Exec::execute(bool exc) throw(std::exception) {
|
||||
stdErr.close_out();
|
||||
if (!stdOut || !stdErr)
|
||||
throw ExecutionFailedExc("cannot close pipe", *_cmd);
|
||||
ssize_t num1(-1), num2(-1);
|
||||
fd_set readfds;
|
||||
char buf[1]; // used to have larger buffer, but since non blocking fails...
|
||||
ssize_t num1(1), num2(1);
|
||||
char buf[4096];
|
||||
int res(0), s(0);
|
||||
/** @bug It sometimes did not get the whole input since I
|
||||
changed to non blocking pipes. Now pipes are blocking
|
||||
again and buffer size is 1, so I hope all problems are
|
||||
resolved. Please report any problems! */
|
||||
while (num1||num2) try { // not all end of file
|
||||
/** @bug @b Solved: It sometimes did not get the whole input
|
||||
since I changed to non blocking pipes. Now I have found
|
||||
the solution to the problems: Non blocking IO does not
|
||||
work in conjunction with @c select! Also the pipe must
|
||||
not be nonblocking on both ends, but only on one. */
|
||||
while (num1||num2||!res) try { // not end of files or child terminated
|
||||
if (!res && (res=waitpid(pid, &s, WNOHANG)))
|
||||
if (res!=pid || WIFEXITED(s)!=0 && WEXITSTATUS(s)!=0)
|
||||
throw ExecutionFailedExc("execution failed", *_cmd);
|
||||
// select...
|
||||
FD_ZERO(&readfds);
|
||||
if (num1) FD_SET(stdOut.istream(), &readfds);
|
||||
if (num2) FD_SET(stdErr.istream(), &readfds);
|
||||
int n(mrw::max((num1?stdOut.istream():0),
|
||||
(num2?stdErr.istream():0)));
|
||||
timeval tm = {0, 10000};
|
||||
int num = select(n+1, &readfds, 0, 0, 0);
|
||||
if (num<0) throw ExecutionFailedExc("select failed", *_cmd);
|
||||
if (num==0 && res==pid) break; // process ended, no data left
|
||||
if (num1<=0&&num2<=0) usleep(10000); // nothing to read last time
|
||||
// check and handle stdout
|
||||
if (num>0 && FD_ISSET(stdOut.istream(), &readfds))
|
||||
if ((num1=read(stdOut.istream(), buf, sizeof(buf)))>0)
|
||||
if (num1 && (num1=read(stdOut.istream(), buf, sizeof(buf)))>0)
|
||||
_res += std::string(buf, num1);
|
||||
else if (num1==-1 && (errno!=EINTR&&errno!=EAGAIN))
|
||||
throw ExecutionFailedExc("readin stdout", *_cmd);
|
||||
// check and handle stderr
|
||||
if (num>0 && FD_ISSET(stdErr.istream(), &readfds))
|
||||
if ((num2=read(stdErr.istream(), buf, sizeof(buf)))>0)
|
||||
if (num2 && (num2=read(stdErr.istream(), buf, sizeof(buf)))>0)
|
||||
_err += std::string(buf, num2);
|
||||
else if (num2==-1 && (errno!=EINTR&&errno!=EAGAIN))
|
||||
throw ExecutionFailedExc("readin stderr", *_cmd);
|
||||
@@ -183,7 +173,6 @@ mrw::Exec& mrw::Exec::execute(bool exc) throw(std::exception) {
|
||||
_success = false;
|
||||
return *this;
|
||||
}
|
||||
std::cout<<"num1="<<num1<<", num2="<<num2<<std::endl;
|
||||
} else { // child
|
||||
stdOut.close_in();
|
||||
stdErr.close_in();
|
||||
@@ -209,8 +198,8 @@ mrw::Exec& mrw::Exec::execute(const std::string& input, bool exc)
|
||||
the program. */
|
||||
_success = false;
|
||||
_res = _err = "";
|
||||
mrw::Pipe stdIn(true), // child terminates if stdin is non-blocking
|
||||
stdOut(true), stdErr(true); // non blocking is also a problem here
|
||||
mrw::Pipe stdIn(mrw::Pipe::block_input),
|
||||
stdOut(mrw::Pipe::block_output), stdErr(mrw::Pipe::block_output);
|
||||
if (!stdIn || !stdOut || !stdErr)
|
||||
throw mrw::ExecutionFailedExc("cannot create pipe", *_cmd);
|
||||
pid_t pid(fork());
|
||||
@@ -221,36 +210,22 @@ mrw::Exec& mrw::Exec::execute(const std::string& input, bool exc)
|
||||
stdErr.close_out();
|
||||
if (!stdIn || !stdOut || !stdErr)
|
||||
throw ExecutionFailedExc("cannot close pipes", *_cmd);
|
||||
ssize_t num0(-1), num1(-1), num2(-1);
|
||||
ssize_t num0(1), num1(1), num2(1);
|
||||
std::string in(input);
|
||||
fd_set writefds, readfds;
|
||||
char buf[1]; // used to have larger buffer, but since non blocking fails...
|
||||
char buf[4096];
|
||||
int res(0), s(0);
|
||||
/** @bug It sometimes did not get the whole input since I
|
||||
changed to non blocking pipes. Now pipes are blocking
|
||||
again and buffer size is 1, so I hope all problems are
|
||||
resolved. Please report any problems! */
|
||||
while (num0||num1||num2) try { // not all end of file
|
||||
/** @bug @b Solved: It sometimes did not get the whole input
|
||||
since I changed to non blocking pipes. Now I have found
|
||||
the solution to the problems: Non blocking IO does not
|
||||
work in conjunction with @c select! Also the pipe must
|
||||
not be nonblocking on both ends, but only on one. */
|
||||
while (num0||num1||num2||!res) try { // not end of files or child terminated
|
||||
if (!res && (res=waitpid(pid, &s, WNOHANG)))
|
||||
if (res!=pid || WIFEXITED(s)!=0 && WEXITSTATUS(s)!=0)
|
||||
throw ExecutionFailedExc("execution failed", *_cmd);
|
||||
// select...
|
||||
FD_ZERO(&writefds);
|
||||
FD_ZERO(&readfds);
|
||||
if (num0) FD_SET(stdIn.ostream(), &writefds);
|
||||
if (num1) FD_SET(stdOut.istream(), &readfds);
|
||||
if (num2) FD_SET(stdErr.istream(), &readfds);
|
||||
int n(mrw::max((num0?stdIn.ostream():0),
|
||||
mrw::max((num1?stdOut.istream():0),
|
||||
(num2?stdErr.istream():0))));
|
||||
timeval tm = {0, 10000};
|
||||
int num = select(n+1, &readfds, &writefds, 0, &tm);
|
||||
if (num<0) throw ExecutionFailedExc("select failed", *_cmd);
|
||||
if (num==0 && res==pid) break; // process ended, no data left
|
||||
if (num0<=0&&num1<=0&&num2<=0) usleep(10000); // no activity last time
|
||||
// check and handle stdin
|
||||
if (num0 && num>0
|
||||
&& FD_ISSET(stdIn.ostream(), &writefds))
|
||||
if ((num0=write(stdIn.ostream(), in.c_str(), in.size()))>0) {
|
||||
if (num0 && (num0=write(stdIn.ostream(), in.c_str(), in.size()))>0) {
|
||||
if ((unsigned int)num0<in.size())
|
||||
in = in.substr(num0);
|
||||
else if ((unsigned int)num0==in.size())
|
||||
@@ -258,14 +233,12 @@ mrw::Exec& mrw::Exec::execute(const std::string& input, bool exc)
|
||||
} else if (num0==-1 && (errno!=EINTR&&errno!=EAGAIN))
|
||||
throw ExecutionFailedExc("writing stdin", *_cmd);
|
||||
// check and handle stdout
|
||||
if (num>0 && FD_ISSET(stdOut.istream(), &readfds))
|
||||
if ((num1=read(stdOut.istream(), buf, sizeof(buf)))>0)
|
||||
if (num1 && (num1=read(stdOut.istream(), buf, sizeof(buf)))>0)
|
||||
_res += std::string(buf, num1);
|
||||
else if (num1==-1 && (errno!=EINTR&&errno!=EAGAIN))
|
||||
throw ExecutionFailedExc("readin stdout", *_cmd);
|
||||
// check and handle stderr
|
||||
if (num>0 && FD_ISSET(stdErr.istream(), &readfds))
|
||||
if ((num2=read(stdErr.istream(), buf, sizeof(buf)))>0)
|
||||
if (num2 && (num2=read(stdErr.istream(), buf, sizeof(buf)))>0)
|
||||
_err += std::string(buf, num2);
|
||||
else if (num2==-1 && (errno!=EINTR&&errno!=EAGAIN))
|
||||
throw ExecutionFailedExc("readin stderr", *_cmd);
|
||||
@@ -274,7 +247,6 @@ mrw::Exec& mrw::Exec::execute(const std::string& input, bool exc)
|
||||
_success = false;
|
||||
return *this;
|
||||
}
|
||||
std::cout<<"num0="<<num0<<", num1="<<num1<<", num2="<<num2<<std::endl;
|
||||
} else { // child
|
||||
stdIn.close_out();
|
||||
stdOut.close_in();
|
||||
|
Reference in New Issue
Block a user