diff --git a/mrw/exec.cpp b/mrw/exec.cpp index a51cf83..4794fe6 100644 --- a/mrw/exec.cpp +++ b/mrw/exec.cpp @@ -9,6 +9,9 @@ @license LGPL, see file COPYING $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 #include #include // max -#include // waitpid -#include // fork, exec -#include // memcpy +#include // waitpid#include // fork, exec +#include // memcpy #include // assert -#include 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,46 +145,34 @@ 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) - _res += std::string(buf, num1); - else if (num1==-1 && (errno!=EINTR&&errno!=EAGAIN)) - throw ExecutionFailedExc("readin stdout", *_cmd); + 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) - _err += std::string(buf, num2); - else if (num2==-1 && (errno!=EINTR&&errno!=EAGAIN)) - throw ExecutionFailedExc("readin stderr", *_cmd); + 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); } catch (...) { if (exc) throw; _success = false; return *this; } - std::cout<<"num1="<0 - && FD_ISSET(stdIn.ostream(), &writefds)) - if ((num0=write(stdIn.ostream(), in.c_str(), in.size()))>0) { - if ((unsigned int)num00) { + if ((unsigned int)num00 && 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); + 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) - _err += std::string(buf, num2); - else if (num2==-1 && (errno!=EINTR&&errno!=EAGAIN)) - throw ExecutionFailedExc("readin stderr", *_cmd); + 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); } catch (...) { if (exc) throw; _success = false; return *this; } - std::cout<<"num0="<