it works perfectly with blocking pipes and buffer size of 1

master
Marc Wäckerlin 20 years ago
parent 67320fbb3f
commit 3e684a3419
  1. 26
      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.7 2004/12/17 17:38:57 marc
it works perfectly with blocking pipes and buffer size of 1
Revision 1.6 2004/12/17 16:28:51 marc Revision 1.6 2004/12/17 16:28:51 marc
stable implementation with select for both executes stable implementation with select for both executes
@ -38,6 +41,7 @@
#include <string.h> // memcpy #include <string.h> // memcpy
#include <assert.h> // assert #include <assert.h> // assert
#include <iostream>
mrw::ExecutionFailedExc::ExecutionFailedExc(const std::string& w, mrw::ExecutionFailedExc::ExecutionFailedExc(const std::string& w,
const std::string& c) const std::string& c)
throw(std::bad_exception): throw(std::bad_exception):
@ -129,7 +133,7 @@ mrw::Exec& mrw::Exec::execute(bool exc) throw(std::exception) {
program. */ program. */
_success = false; _success = false;
_res = _err = ""; _res = _err = "";
mrw::Pipe stdOut, stdErr; mrw::Pipe stdOut(true), stdErr(true);
if (!stdOut || !stdErr) if (!stdOut || !stdErr)
throw mrw::ExecutionFailedExc("cannot create pipe", *_cmd); throw mrw::ExecutionFailedExc("cannot create pipe", *_cmd);
pid_t pid(fork()); pid_t pid(fork());
@ -142,8 +146,12 @@ mrw::Exec& mrw::Exec::execute(bool exc) throw(std::exception) {
throw ExecutionFailedExc("cannot close pipe", *_cmd); throw ExecutionFailedExc("cannot close pipe", *_cmd);
ssize_t num1(-1), num2(-1); ssize_t num1(-1), num2(-1);
fd_set readfds; fd_set readfds;
char buf[4096]; char buf[1]; // used to have larger buffer, but since non blocking fails...
int res(0), s(0); 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 while (num1||num2) try { // not all end of file
if (!res && (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)
@ -155,7 +163,7 @@ mrw::Exec& mrw::Exec::execute(bool exc) throw(std::exception) {
int n(mrw::max((num1?stdOut.istream():0), int n(mrw::max((num1?stdOut.istream():0),
(num2?stdErr.istream():0))); (num2?stdErr.istream():0)));
timeval tm = {0, 10000}; timeval tm = {0, 10000};
int num = select(n, &readfds, 0, 0, &tm); int num = select(n+1, &readfds, 0, 0, 0);
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 if (num==0 && res==pid) break; // process ended, no data left
// check and handle stdout // check and handle stdout
@ -175,6 +183,7 @@ mrw::Exec& mrw::Exec::execute(bool exc) throw(std::exception) {
_success = false; _success = false;
return *this; return *this;
} }
std::cout<<"num1="<<num1<<", num2="<<num2<<std::endl;
} else { // child } else { // child
stdOut.close_in(); stdOut.close_in();
stdErr.close_in(); stdErr.close_in();
@ -201,7 +210,7 @@ mrw::Exec& mrw::Exec::execute(const std::string& input, bool exc)
_success = false; _success = false;
_res = _err = ""; _res = _err = "";
mrw::Pipe stdIn(true), // child terminates if stdin is non-blocking mrw::Pipe stdIn(true), // child terminates if stdin is non-blocking
stdOut, stdErr; stdOut(true), stdErr(true); // non blocking is also a problem here
if (!stdIn || !stdOut || !stdErr) if (!stdIn || !stdOut || !stdErr)
throw mrw::ExecutionFailedExc("cannot create pipe", *_cmd); throw mrw::ExecutionFailedExc("cannot create pipe", *_cmd);
pid_t pid(fork()); pid_t pid(fork());
@ -215,8 +224,12 @@ mrw::Exec& mrw::Exec::execute(const std::string& input, bool exc)
ssize_t num0(-1), num1(-1), num2(-1); ssize_t num0(-1), num1(-1), num2(-1);
std::string in(input); std::string in(input);
fd_set writefds, readfds; fd_set writefds, readfds;
char buf[4096]; char buf[1]; // used to have larger buffer, but since non blocking fails...
int res(0), s(0); 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 while (num0||num1||num2) try { // not all end of file
if (!res && (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)
@ -231,7 +244,7 @@ mrw::Exec& mrw::Exec::execute(const std::string& input, bool exc)
mrw::max((num1?stdOut.istream():0), mrw::max((num1?stdOut.istream():0),
(num2?stdErr.istream():0)))); (num2?stdErr.istream():0))));
timeval tm = {0, 10000}; timeval tm = {0, 10000};
int num = select(n, &readfds, &writefds, 0, &tm); int num = select(n+1, &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 if (num==0 && res==pid) break; // process ended, no data left
// check and handle stdin // check and handle stdin
@ -261,6 +274,7 @@ mrw::Exec& mrw::Exec::execute(const std::string& input, bool exc)
_success = false; _success = false;
return *this; return *this;
} }
std::cout<<"num0="<<num0<<", num1="<<num1<<", num2="<<num2<<std::endl;
} else { // child } else { // child
stdIn.close_out(); stdIn.close_out();
stdOut.close_in(); stdOut.close_in();

Loading…
Cancel
Save