|
|
@ -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(); |
|
|
|