stable implementation with select for both executes

master
Marc Wäckerlin 20 years ago
parent f13b5a47b7
commit 2a47dd7863
  1. 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();

Loading…
Cancel
Save