Loading ccsrc/Helpers/async_process.cc +25 −4 Original line number Diff line number Diff line #include "async_process.hh" void async_process::start(const std::string& command, const std::vector<std::string>& args, Options opts) { void async_process::start(const std::string& command, const std::vector<std::string>& args, Options opts, std::chrono::milliseconds timeout) { // Sanity check if (running_) throw std::runtime_error("Process already running"); Loading Loading @@ -31,6 +31,12 @@ void async_process::start(const std::string& command, const std::vector<std::str if (opts_.onOutput) { reader_ = std::thread([this] { pumpOutput(); }); } auto deadline = std::chrono::steady_clock::now() + timeout; int status = 0; while (std::chrono::steady_clock::now() < deadline) { std::this_thread::sleep_for(std::chrono::milliseconds(50)); } } bool async_process::pollExitStatus(int& status) { Loading Loading @@ -66,10 +72,25 @@ int async_process::wait() { return exitStatus_; } void async_process::terminate(int signalNo) { if (pid_ > 0 && running_) { int async_process::terminate(int signalNo, std::chrono::milliseconds timeout) { if (pid_ <= 0 or !running_) { return -1; } ::kill(pid_, signalNo); auto deadline = std::chrono::steady_clock::now() + timeout; int status = 0; while (std::chrono::steady_clock::now() < deadline) { pid_t r = ::waitpid(pid_, &status, WNOHANG); if (r == pid_) return 0; // child exited if (r < 0) return -1; // error std::this_thread::sleep_for(std::chrono::milliseconds(10)); } ::kill(pid_, SIGKILL); return (::waitpid(pid_, &status, 0) == pid_) ? 0 : -1; } void async_process::setNonBlocking(int fd) { Loading ccsrc/Helpers/async_process.hh +3 −3 Original line number Diff line number Diff line Loading @@ -30,13 +30,13 @@ public: async_process(const async_process&) = delete; async_process& operator=(const async_process&) = delete; void start(const std::string& command, const std::vector<std::string>& args, Options opts); void start(const std::string& command, const std::vector<std::string>& args, Options opts, std::chrono::milliseconds timeout = std::chrono::milliseconds(2000)); bool pollExitStatus(int& status); int wait(); void terminate(int signalNo = SIGTERM); int terminate(int signalNo = SIGTERM, std::chrono::milliseconds timeout = std::chrono::milliseconds(5000)); inline bool running() const noexcept { return running_ && !exited_; }; inline void killForce() { terminate(SIGKILL); }; inline void killForce() { terminate(SIGTERM); }; // Clean termination of the process, with SIGTERM signal inline std::string readStdout() { return drainFd(stdoutPipe_[0]); }; inline std::string readStderr() { return drainFd(stderrPipe_[0]); }; inline pid_t pid() const noexcept { return pid_; }; Loading Loading
ccsrc/Helpers/async_process.cc +25 −4 Original line number Diff line number Diff line #include "async_process.hh" void async_process::start(const std::string& command, const std::vector<std::string>& args, Options opts) { void async_process::start(const std::string& command, const std::vector<std::string>& args, Options opts, std::chrono::milliseconds timeout) { // Sanity check if (running_) throw std::runtime_error("Process already running"); Loading Loading @@ -31,6 +31,12 @@ void async_process::start(const std::string& command, const std::vector<std::str if (opts_.onOutput) { reader_ = std::thread([this] { pumpOutput(); }); } auto deadline = std::chrono::steady_clock::now() + timeout; int status = 0; while (std::chrono::steady_clock::now() < deadline) { std::this_thread::sleep_for(std::chrono::milliseconds(50)); } } bool async_process::pollExitStatus(int& status) { Loading Loading @@ -66,10 +72,25 @@ int async_process::wait() { return exitStatus_; } void async_process::terminate(int signalNo) { if (pid_ > 0 && running_) { int async_process::terminate(int signalNo, std::chrono::milliseconds timeout) { if (pid_ <= 0 or !running_) { return -1; } ::kill(pid_, signalNo); auto deadline = std::chrono::steady_clock::now() + timeout; int status = 0; while (std::chrono::steady_clock::now() < deadline) { pid_t r = ::waitpid(pid_, &status, WNOHANG); if (r == pid_) return 0; // child exited if (r < 0) return -1; // error std::this_thread::sleep_for(std::chrono::milliseconds(10)); } ::kill(pid_, SIGKILL); return (::waitpid(pid_, &status, 0) == pid_) ? 0 : -1; } void async_process::setNonBlocking(int fd) { Loading
ccsrc/Helpers/async_process.hh +3 −3 Original line number Diff line number Diff line Loading @@ -30,13 +30,13 @@ public: async_process(const async_process&) = delete; async_process& operator=(const async_process&) = delete; void start(const std::string& command, const std::vector<std::string>& args, Options opts); void start(const std::string& command, const std::vector<std::string>& args, Options opts, std::chrono::milliseconds timeout = std::chrono::milliseconds(2000)); bool pollExitStatus(int& status); int wait(); void terminate(int signalNo = SIGTERM); int terminate(int signalNo = SIGTERM, std::chrono::milliseconds timeout = std::chrono::milliseconds(5000)); inline bool running() const noexcept { return running_ && !exited_; }; inline void killForce() { terminate(SIGKILL); }; inline void killForce() { terminate(SIGTERM); }; // Clean termination of the process, with SIGTERM signal inline std::string readStdout() { return drainFd(stdoutPipe_[0]); }; inline std::string readStderr() { return drainFd(stderrPipe_[0]); }; inline pid_t pid() const noexcept { return pid_; }; Loading