stable implementation with select for both executes
This commit is contained in:
78
mrw/exec.cpp
78
mrw/exec.cpp
@@ -9,6 +9,9 @@
|
|||||||
@license LGPL, see file <a href="license.html">COPYING</a>
|
@license LGPL, see file <a href="license.html">COPYING</a>
|
||||||
|
|
||||||
$Log$
|
$Log$
|
||||||
|
Revision 1.6 2004/12/17 16:28:51 marc
|
||||||
|
stable implementation with select for both executes
|
||||||
|
|
||||||
Revision 1.5 2004/12/14 20:30:09 marc
|
Revision 1.5 2004/12/14 20:30:09 marc
|
||||||
added possibility to pass string to stdin of child process
|
added possibility to pass string to stdin of child process
|
||||||
|
|
||||||
@@ -137,25 +140,40 @@ mrw::Exec& mrw::Exec::execute(bool exc) throw(std::exception) {
|
|||||||
stdErr.close_out();
|
stdErr.close_out();
|
||||||
if (!stdOut || !stdErr)
|
if (!stdOut || !stdErr)
|
||||||
throw ExecutionFailedExc("cannot close pipe", *_cmd);
|
throw ExecutionFailedExc("cannot close pipe", *_cmd);
|
||||||
int num1(0), num2(0);
|
ssize_t num1(-1), num2(-1);
|
||||||
for (char buf1[4096], buf2[4096];
|
fd_set readfds;
|
||||||
(num1=read(stdOut.istream(), buf1, sizeof(buf1)))>0
|
char buf[4096];
|
||||||
|| num1==-1 && (errno==EINTR||errno==EAGAIN)
|
int res(0), s(0);
|
||||||
|| (num2=read(stdErr.istream(), buf2, sizeof(buf2)))>0
|
while (num1||num2) try { // not all end of file
|
||||||
|| num2==-1 && (errno==EINTR||errno==EAGAIN);) {
|
if (!res && (res=waitpid(pid, &s, WNOHANG)))
|
||||||
if (num1>0) _res += std::string(buf1, num1);
|
if (res!=pid || WIFEXITED(s)!=0 && WEXITSTATUS(s)!=0)
|
||||||
if (num2>0) _err += std::string(buf2, num2);
|
throw ExecutionFailedExc("execution failed", *_cmd);
|
||||||
}
|
// select...
|
||||||
// wait for child to get return code
|
FD_ZERO(&readfds);
|
||||||
int s(0);
|
if (num1) FD_SET(stdOut.istream(), &readfds);
|
||||||
if (waitpid(pid, &s, 0)!=pid || WIFEXITED(s)!=0 && WEXITSTATUS(s)!=0
|
if (num2) FD_SET(stdErr.istream(), &readfds);
|
||||||
|| num1==-1 || num2==-1) {
|
int n(mrw::max((num1?stdOut.istream():0),
|
||||||
if (exc) {
|
(num2?stdErr.istream():0)));
|
||||||
throw ExecutionFailedExc("execution failed", *_cmd);
|
timeval tm = {0, 10000};
|
||||||
} else {
|
int num = select(n, &readfds, 0, 0, &tm);
|
||||||
_success = false;
|
if (num<0) throw ExecutionFailedExc("select failed", *_cmd);
|
||||||
return *this;
|
if (num==0 && res==pid) break; // process ended, no data left
|
||||||
}
|
// check and handle stdout
|
||||||
|
if (num>0 && FD_ISSET(stdOut.istream(), &readfds))
|
||||||
|
if ((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)
|
||||||
|
_err += std::string(buf, num2);
|
||||||
|
else if (num2==-1 && (errno!=EINTR&&errno!=EAGAIN))
|
||||||
|
throw ExecutionFailedExc("readin stderr", *_cmd);
|
||||||
|
} catch (...) {
|
||||||
|
if (exc) throw;
|
||||||
|
_success = false;
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
} else { // child
|
} else { // child
|
||||||
stdOut.close_in();
|
stdOut.close_in();
|
||||||
@@ -198,26 +216,24 @@ mrw::Exec& mrw::Exec::execute(const std::string& input, bool exc)
|
|||||||
std::string in(input);
|
std::string in(input);
|
||||||
fd_set writefds, readfds;
|
fd_set writefds, readfds;
|
||||||
char buf[4096];
|
char buf[4096];
|
||||||
while (num0 || num1 || num2) try { // no end of file in stdin, -out, -err
|
int res(0), s(0);
|
||||||
int res(0), s(0);
|
while (num0||num1||num2) try { // not all end of file
|
||||||
if ((res=waitpid(pid, &s, WNOHANG))) {
|
if (!res && (res=waitpid(pid, &s, WNOHANG)))
|
||||||
if (res!=pid || WIFEXITED(s)!=0 && WEXITSTATUS(s)!=0)
|
if (res!=pid || WIFEXITED(s)!=0 && WEXITSTATUS(s)!=0)
|
||||||
throw ExecutionFailedExc("execution failed", *_cmd);
|
throw ExecutionFailedExc("execution failed", *_cmd);
|
||||||
_success = true;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
// select...
|
// select...
|
||||||
FD_ZERO(&writefds);
|
FD_ZERO(&writefds);
|
||||||
FD_ZERO(&readfds);
|
FD_ZERO(&readfds);
|
||||||
if (num0) FD_SET(stdIn.ostream(), &writefds);
|
if (num0) FD_SET(stdIn.ostream(), &writefds);
|
||||||
if (num1) FD_SET(stdOut.istream(), &readfds);
|
if (num1) FD_SET(stdOut.istream(), &readfds);
|
||||||
if (num2) FD_SET(stdErr.istream(), &readfds);
|
if (num2) FD_SET(stdErr.istream(), &readfds);
|
||||||
timeval tm = {1, 0};
|
|
||||||
int n(mrw::max((num0?stdIn.ostream():0),
|
int n(mrw::max((num0?stdIn.ostream():0),
|
||||||
mrw::max((num1?stdOut.istream():0),
|
mrw::max((num1?stdOut.istream():0),
|
||||||
(num2?stdErr.istream():0))));
|
(num2?stdErr.istream():0))));
|
||||||
|
timeval tm = {0, 10000};
|
||||||
int num = select(n, &readfds, &writefds, 0, &tm);
|
int num = select(n, &readfds, &writefds, 0, &tm);
|
||||||
if (num<0) throw ExecutionFailedExc("select failed", *_cmd);
|
if (num<0) throw ExecutionFailedExc("select failed", *_cmd);
|
||||||
|
if (num==0 && res==pid) break; // process ended, no data left
|
||||||
// check and handle stdin
|
// check and handle stdin
|
||||||
if (num0 && num>0
|
if (num0 && num>0
|
||||||
&& FD_ISSET(stdIn.ostream(), &writefds))
|
&& FD_ISSET(stdIn.ostream(), &writefds))
|
||||||
@@ -245,16 +261,6 @@ mrw::Exec& mrw::Exec::execute(const std::string& input, bool exc)
|
|||||||
_success = false;
|
_success = false;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
// wait for child to get return code
|
|
||||||
int s(0);
|
|
||||||
if (waitpid(pid, &s, 0)!=pid || WIFEXITED(s)!=0 && WEXITSTATUS(s)!=0) {
|
|
||||||
if (exc) {
|
|
||||||
throw ExecutionFailedExc("execution failed", *_cmd);
|
|
||||||
} else {
|
|
||||||
_success = false;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else { // child
|
} else { // child
|
||||||
stdIn.close_out();
|
stdIn.close_out();
|
||||||
stdOut.close_in();
|
stdOut.close_in();
|
||||||
|
Reference in New Issue
Block a user