25#include <boost/make_shared.hpp>
28namespace ph = std::placeholders;
56class processSpawnImpl;
89 const std::string& executable,
92 const bool inherit_env,
115 pid_t
spawn(
bool dismiss);
154 class IOSignalSetInitializer {
165 boost::make_shared<IOSignalSet>(io_service,
166 std::bind(&ProcessSpawnImpl::waitForProcess, ph::_1,
168 io_signal_set_->add(SIGCHLD);
172 ~IOSignalSetInitializer() {
173 io_signal_set_->remove(SIGCHLD);
204 char* allocateInternal(
const std::string& src);
214 static void waitForProcess(
int signum, pid_t
const wpid = -1,
bool const sync =
false);
220 std::string executable_;
223 boost::shared_ptr<char*[]> args_;
226 boost::shared_ptr<char*[]> vars_;
229 typedef boost::shared_ptr<char[]> CStringPtr;
232 std::vector<CStringPtr> storage_;
238 static std::mutex mutex_;
249std::mutex ProcessSpawnImpl::mutex_;
251void ProcessSpawnImpl::IOSignalSetInitializer::initIOSignalSet(
IOServicePtr io_service) {
252 static IOSignalSetInitializer init(io_service);
256 const std::string& executable,
259 const bool inherit_env,
261 : executable_(executable), args_(new char*[args.size() + 2]),
262 store_(false), io_service_(io_service), sync_(sync) {
271 vars_size = i + vars.size();
273 vars_size = vars.size();
276 vars_ = boost::shared_ptr<char*[]>(
new char*[vars_size + 1]);
280 if (stat(executable_.c_str(), &st)) {
284 if (!(st.st_mode & S_IEXEC)) {
291 memset(args_.get(), 0, (args.size() + 2) *
sizeof(
char*));
292 memset(vars_.get(), 0, (vars_size + 1) *
sizeof(
char*));
294 args_[0] = allocateInternal(executable_);
296 for (
size_t i = 1; i <= args.size(); ++i) {
297 args_[i] = allocateInternal(args[i - 1]);
303 vars_[i] = allocateInternal(
environ[i]);
307 for (
size_t j = 0; j < vars.size(); ++j) {
308 vars_[i + j] = allocateInternal(vars[j]);
314 lock_guard<std::mutex> lk(mutex_);
315 process_collection_.erase(
this);
321 std::ostringstream s;
327 while (args_[i] != NULL) {
328 s <<
" " << args_[i];
336 lock_guard<std::mutex> lk(mutex_);
338 ProcessSpawnImpl::IOSignalSetInitializer::initIOSignalSet(io_service_);
345 }
else if (pid == 0) {
349 pthread_sigmask(SIG_SETMASK, &sset, 0);
351 execve(executable_.c_str(), args_.get(), vars_.get());
364 waitForProcess(SIGCHLD, pid,
true);
372 lock_guard<std::mutex> lk(mutex_);
373 ProcessStates::const_iterator proc;
374 if (process_collection_.find(
this) == process_collection_.end() ||
375 (proc = process_collection_[
this].find(pid)) == process_collection_[
this].end()) {
378 return (proc->second->running_);
383 lock_guard<std::mutex> lk(mutex_);
384 if (process_collection_.find(
this) != process_collection_.end()) {
385 for (
auto const& proc : process_collection_[
this]) {
386 if (proc.second->running_) {
396 lock_guard<std::mutex> lk(mutex_);
397 ProcessStates::const_iterator proc;
398 if (process_collection_.find(
this) == process_collection_.end() ||
399 (proc = process_collection_[
this].find(pid)) == process_collection_[
this].end()) {
402 return (WEXITSTATUS(proc->second->status_));
406ProcessSpawnImpl::allocateInternal(
const std::string& src) {
407 const size_t src_len = src.length();
408 storage_.push_back(CStringPtr(
new char[src_len + 1]));
410 char* dest = storage_[storage_.size() - 1].get();
412 src.copy(dest, src_len);
414 dest[src_len] =
'\0';
419ProcessSpawnImpl::waitForProcess(
int ,
424 unique_lock<std::mutex> lk{mutex_, std::defer_lock};
434 pid_t pid = waitpid(wpid, &status, sync ? 0 : WNOHANG);
439 if (errno == EINTR) {
445 isc_throw(InvalidOperation,
"process with pid " << wpid <<
" has returned " << pid
446 <<
" from waitpid in sync mode, errno: "
448 }
else if (pid == 0) {
453 for (
auto const& instance : process_collection_) {
454 auto const& proc = instance.second.find(pid);
457 if (proc != instance.second.end()) {
458 proc->second->status_ = status;
459 proc->second->running_ =
false;
474 "process (pid: " << pid <<
") which is still running");
476 lock_guard<std::mutex> lk(mutex_);
477 if (process_collection_.find(
this) != process_collection_.end()) {
478 process_collection_[
this].erase(pid);
483 const std::string& executable,
486 const bool inherit_env )
498 const bool inherit_env )
509 return (impl_->getCommandLine());
514 return (impl_->spawn(dismiss));
519 return (impl_->isRunning(pid));
524 return (impl_->isAnyRunning());
529 return (impl_->getExitStatus(pid));
534 return (impl_->clearState(pid));
A generic exception that is thrown if a function is called in a prohibited way.
The IOService class is a wrapper for the ASIO io_service class.
Exception thrown when error occurs during spawning a process.
Implementation of the ProcessSpawn class.
void clearState(const pid_t pid)
Removes the status of the process with a specified PID.
bool isAnyRunning() const
Checks if any of the spawned processes is still running.
std::string getCommandLine() const
Returns full command line, including arguments, for the process.
ProcessSpawnImpl(IOServicePtr io_service, const std::string &executable, const ProcessArgs &args, const ProcessEnvVars &vars, const bool inherit_env, const bool sync)
Constructor.
pid_t spawn(bool dismiss)
Spawn the new process.
~ProcessSpawnImpl()
Destructor.
bool isRunning(const pid_t pid) const
Checks if the process is still running.
int getExitStatus(const pid_t pid) const
Returns exit status of the process.
bool isAnyRunning() const
Checks if any of the spawned processes is still running.
int getExitStatus(const pid_t pid) const
Returns exit status of the process.
void clearState(const pid_t pid)
Removes the status of the process with a specified PID.
bool isRunning(const pid_t pid) const
Checks if the process is still running.
std::string getCommandLine() const
Returns full command line, including arguments, for the process.
pid_t spawn(bool dismiss=false)
Spawn the new process.
ProcessSpawn(isc::asiolink::IOServicePtr io_service, const std::string &executable, const ProcessArgs &args=ProcessArgs(), const ProcessEnvVars &vars=ProcessEnvVars(), const bool inherit_env=false)
Constructor.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
A wrapper interface for the ASIO library.
std::map< const ProcessSpawnImpl *, ProcessStates > ProcessCollection
ProcessCollection container which stores all ProcessStates for each instance of ProcessSpawnImpl.
std::vector< std::string > ProcessArgs
Type of the container holding arguments of the executable being run as a background process.
boost::shared_ptr< ProcessState > ProcessStatePtr
Defines a pointer to a ProcessState.
std::vector< std::string > ProcessEnvVars
Type of the container holding environment variables of the executable being run as a background proce...
std::map< pid_t, ProcessStatePtr > ProcessStates
ProcessStates container which stores a ProcessState for each process identified by PID.
boost::shared_ptr< IOService > IOServicePtr
Defines a smart pointer to an IOService instance.
boost::shared_ptr< IOSignalSet > IOSignalSetPtr
Defines a pointer to an IOSignalSet.
Defines the logger used by the top-level component of kea-lfc.
bool running_
true until the exit status is collected
ProcessState()
Constructor.
int status_
0 or the exit status