mirror of
https://github.com/arun11299/cpp-subprocess.git
synced 2025-08-05 04:46:21 -04:00
fix a bug of defunct process by adding a SIGCHLD handler.
This commit is contained in:
parent
a23c1033df
commit
814be9e635
@ -42,6 +42,7 @@ Documentation for C++ subprocessing libraray.
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <csignal>
|
||||
#include <future>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
@ -53,7 +54,7 @@ extern "C" {
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/wait.h>
|
||||
#include <signal.h>
|
||||
}
|
||||
|
||||
@ -67,7 +68,7 @@ extern "C" {
|
||||
* library: OSError and CalledProcessError
|
||||
*
|
||||
* 2. Popen Class
|
||||
* This is the main class the users will deal with. It
|
||||
* This is the main class the users will deal with. It
|
||||
* provides with all the API's to deal with processes.
|
||||
*
|
||||
* 3. Util namespace
|
||||
@ -89,11 +90,11 @@ static const size_t SP_MAX_ERR_BUF_SIZ = 1024;
|
||||
// Default buffer capcity for OutBuffer and ErrBuffer.
|
||||
// If the data exceeds this capacity, the buffer size is grown
|
||||
// by 1.5 times its previous capacity
|
||||
static const size_t DEFAULT_BUF_CAP_BYTES = 8192;
|
||||
static const size_t DEFAULT_BUF_CAP_BYTES = 8192;
|
||||
|
||||
|
||||
/*-----------------------------------------------
|
||||
* EXCEPTION CLASSES
|
||||
* EXCEPTION CLASSES
|
||||
*-----------------------------------------------
|
||||
*/
|
||||
|
||||
@ -139,7 +140,7 @@ namespace util
|
||||
/*!
|
||||
* Function: split
|
||||
* Parameters:
|
||||
* [in] str : Input string which needs to be split based upon the
|
||||
* [in] str : Input string which needs to be split based upon the
|
||||
* delimiters provided.
|
||||
* [in] deleims : Delimiter characters based upon which the string needs
|
||||
* to be split. Default constructed to ' '(space) and '\t'(tab)
|
||||
@ -258,7 +259,7 @@ namespace util
|
||||
|
||||
/*!
|
||||
* Function: read_atmost_n
|
||||
* Reads at the most `read_upto` bytes from the
|
||||
* Reads at the most `read_upto` bytes from the
|
||||
* file descriptor `fd` before returning.
|
||||
* Parameters:
|
||||
* [in] fd : The file descriptor from which it needs to read.
|
||||
@ -355,7 +356,7 @@ namespace util
|
||||
int status = 0;
|
||||
int ret = -1;
|
||||
while (1) {
|
||||
ret = waitpid(pid, &status, WNOHANG);
|
||||
ret = waitpid(pid, &status, WNOHANG);
|
||||
if (ret == -1) break;
|
||||
if (ret == 0) continue;
|
||||
return std::make_pair(ret, status);
|
||||
@ -379,7 +380,7 @@ namespace util
|
||||
* streams of the child process.
|
||||
* Default value is 0.
|
||||
*/
|
||||
struct bufsize {
|
||||
struct bufsize {
|
||||
bufsize(int siz): bufsiz(siz) {}
|
||||
int bufsiz = 0;
|
||||
};
|
||||
@ -389,7 +390,7 @@ struct bufsize {
|
||||
* till `Popen::start_process` API is called.
|
||||
* Default value is false.
|
||||
*/
|
||||
struct defer_spawn {
|
||||
struct defer_spawn {
|
||||
defer_spawn(bool d): defer(d) {}
|
||||
bool defer = false;
|
||||
};
|
||||
@ -403,7 +404,7 @@ struct defer_spawn {
|
||||
*
|
||||
* Default value is false.
|
||||
*/
|
||||
struct close_fds {
|
||||
struct close_fds {
|
||||
close_fds(bool c): close_all(c) {}
|
||||
bool close_all = false;
|
||||
};
|
||||
@ -438,7 +439,7 @@ struct string_arg
|
||||
/*!
|
||||
* Option to specify the executable name seperately
|
||||
* from the args sequence.
|
||||
* In this case the cmd args must only contain the
|
||||
* In this case the cmd args must only contain the
|
||||
* options required for this executable.
|
||||
*
|
||||
* Eg: executable{"ls"}
|
||||
@ -480,7 +481,7 @@ struct environment
|
||||
/*!
|
||||
* Used for redirecting input/output/error
|
||||
*/
|
||||
enum IOTYPE {
|
||||
enum IOTYPE {
|
||||
STDOUT = 1,
|
||||
STDERR,
|
||||
PIPE,
|
||||
@ -568,7 +569,7 @@ struct error
|
||||
error(FILE* fp):error(fileno(fp)) { assert(fp); }
|
||||
|
||||
error(const char* filename) {
|
||||
int fd = open(filename, O_APPEND | O_CREAT | O_RDWR, 0640);
|
||||
int fd = open(filename, O_APPEND | O_CREAT | O_RDWR, 0640);
|
||||
if (fd == -1) throw OSError("File not found: ", errno);
|
||||
wr_ch_ = fd;
|
||||
}
|
||||
@ -593,7 +594,7 @@ struct error
|
||||
// ATTN: Can be used only to execute functions with no
|
||||
// arguments and returning void.
|
||||
// Could have used more efficient methods, ofcourse, but
|
||||
// that wont yield me the consistent syntax which I am
|
||||
// that wont yield me the consistent syntax which I am
|
||||
// aiming for. If you know, then please do let me know.
|
||||
|
||||
class preexec_func
|
||||
@ -711,11 +712,11 @@ struct has_type<F, param_pack<H,T...>> {
|
||||
//----
|
||||
|
||||
/*!
|
||||
* A helper class to Popen class for setting
|
||||
* A helper class to Popen class for setting
|
||||
* options as provided in the Popen constructor
|
||||
* or in check_ouput arguments.
|
||||
* This design allows us to _not_ have any fixed position
|
||||
* to any arguments and specify them in a way similar to what
|
||||
* to any arguments and specify them in a way similar to what
|
||||
* can be done in python.
|
||||
*/
|
||||
struct ArgumentDeducer
|
||||
@ -755,7 +756,7 @@ public:
|
||||
void execute_child();
|
||||
|
||||
private:
|
||||
// Lets call it parent even though
|
||||
// Lets call it parent even though
|
||||
// technically a bit incorrect
|
||||
Popen* parent_ = nullptr;
|
||||
int err_wr_pipe_ = -1;
|
||||
@ -803,7 +804,7 @@ private:
|
||||
* This is a helper class to Popen.
|
||||
* It takes care of management of all the file descriptors
|
||||
* and file pointers.
|
||||
* It dispatches of the communication aspects to the
|
||||
* It dispatches of the communication aspects to the
|
||||
* Communication class.
|
||||
* Read through the data members to understand about the
|
||||
* various file descriptors used.
|
||||
@ -935,7 +936,7 @@ public:
|
||||
friend class detail::Child;
|
||||
|
||||
template <typename... Args>
|
||||
Popen(const std::string& cmd_args, Args&& ...args):
|
||||
Popen(const std::string& cmd_args, Args&& ...args):
|
||||
args_(cmd_args)
|
||||
{
|
||||
vargs_ = util::split(cmd_args);
|
||||
@ -977,7 +978,7 @@ public:
|
||||
|
||||
void set_err_buf_cap(size_t cap) { stream_.set_err_buf_cap(cap); }
|
||||
|
||||
int send(const char* msg, size_t length)
|
||||
int send(const char* msg, size_t length)
|
||||
{ return stream_.send(msg, length); }
|
||||
|
||||
int send(const std::vector<char>& msg)
|
||||
@ -1150,6 +1151,11 @@ void Popen::execute_process() throw (CalledProcessError, OSError)
|
||||
}
|
||||
exe_name_ = vargs_[0];
|
||||
|
||||
std::signal(SIGCHLD, [](int sig){
|
||||
int status;
|
||||
waitpid(-1, &status, WNOHANG);
|
||||
});
|
||||
|
||||
child_pid_ = fork();
|
||||
|
||||
if (child_pid_ < 0) {
|
||||
@ -1170,8 +1176,8 @@ void Popen::execute_process() throw (CalledProcessError, OSError)
|
||||
|
||||
detail::Child chld(this, err_wr_pipe);
|
||||
chld.execute_child();
|
||||
}
|
||||
else
|
||||
}
|
||||
else
|
||||
{
|
||||
int sys_ret = -1;
|
||||
close (err_wr_pipe);// close child side of pipe, else get stuck in read below
|
||||
@ -1182,8 +1188,8 @@ void Popen::execute_process() throw (CalledProcessError, OSError)
|
||||
char err_buf[SP_MAX_ERR_BUF_SIZ] = {0,};
|
||||
|
||||
int read_bytes = util::read_atmost_n(
|
||||
err_rd_pipe,
|
||||
err_buf,
|
||||
err_rd_pipe,
|
||||
err_buf,
|
||||
SP_MAX_ERR_BUF_SIZ);
|
||||
close(err_rd_pipe);
|
||||
|
||||
@ -1301,13 +1307,13 @@ namespace detail {
|
||||
_dup2_(stream.err_write_, 2); // Error stream
|
||||
|
||||
// Close the duped descriptors
|
||||
if (stream.read_from_parent_ != -1 && stream.read_from_parent_ > 2)
|
||||
if (stream.read_from_parent_ != -1 && stream.read_from_parent_ > 2)
|
||||
close(stream.read_from_parent_);
|
||||
|
||||
if (stream.write_to_parent_ != -1 && stream.write_to_parent_ > 2)
|
||||
if (stream.write_to_parent_ != -1 && stream.write_to_parent_ > 2)
|
||||
close(stream.write_to_parent_);
|
||||
|
||||
if (stream.err_write_ != -1 && stream.err_write_ > 2)
|
||||
if (stream.err_write_ != -1 && stream.err_write_ > 2)
|
||||
close(stream.err_write_);
|
||||
|
||||
// Close all the inherited fd's except the error write pipe
|
||||
@ -1444,7 +1450,7 @@ namespace detail {
|
||||
|
||||
int rbytes = util::read_atmost_n(
|
||||
fileno(stream_->error()),
|
||||
ebuf.buf.data(),
|
||||
ebuf.buf.data(),
|
||||
ebuf.buf.size());
|
||||
|
||||
if (rbytes == -1) {
|
||||
@ -1538,12 +1544,12 @@ namespace detail
|
||||
{
|
||||
return Popen(std::forward<F>(farg), std::forward<Args>(args)...).wait();
|
||||
}
|
||||
|
||||
|
||||
void pipeline_impl(std::vector<Popen>& cmds) { /* EMPTY IMPL */ }
|
||||
|
||||
template<typename... Args>
|
||||
void pipeline_impl(std::vector<Popen>& cmds,
|
||||
const std::string& cmd,
|
||||
void pipeline_impl(std::vector<Popen>& cmds,
|
||||
const std::string& cmd,
|
||||
Args&&... args)
|
||||
{
|
||||
if (cmds.size() == 0) {
|
||||
@ -1565,7 +1571,7 @@ namespace detail
|
||||
|
||||
/*!
|
||||
* Run the command with arguments and wait for it to complete.
|
||||
* The parameters passed to the argument are exactly the same
|
||||
* The parameters passed to the argument are exactly the same
|
||||
* one would use for Popen constructors.
|
||||
*/
|
||||
template<typename... Args>
|
||||
|
Loading…
x
Reference in New Issue
Block a user