| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199 |
- //
- // ProcessRunner.h
- //
- // Library: Foundation
- // Package: Processes
- // Module: ProcessRunner
- //
- // Definition of the ProcessRunner class.
- //
- // Copyright (c) 2023, Applied Informatics Software Engineering GmbH.
- // Aleph ONE Software Engineering d.o.o.,
- // and Contributors.
- //
- // SPDX-License-Identifier: BSL-1.0
- //
- #ifndef Foundation_ProcessRunner_INCLUDED
- #define Foundation_ProcessRunner_INCLUDED
- #include "Poco/Foundation.h"
- #include "Poco/Process.h"
- #include "Poco/ProcessOptions.h"
- #include "Poco/Runnable.h"
- #include "Poco/Thread.h"
- #include "Poco/Format.h"
- #include "Poco/Stopwatch.h"
- #include <atomic>
- #include <vector>
- namespace Poco {
- class Foundation_API ProcessRunner: public Poco::Runnable
- /// ProcessRunner is a wrapper class for `Poco::ProcessHandle.
- /// It starts and terminates a process with enabled or disabled (default)
- /// `stdio` pipes, and optionally waits for process PID to be created before
- /// returning control to the caller. The process is spawned from an
- /// internal thread. Starting/stopping the process may block up to
- /// a certain (configurable) period of time.
- ///
- /// ProcessRunner can hold and control only one process at a time, which
- /// can be started/stopped multiple times during the ProcessRunner lifetime.
- {
- public:
- using Args = Poco::Process::Args;
- using PID = Poco::ProcessHandle::PID;
- static const int NO_OUT = Poco::PROCESS_CLOSE_STDOUT|Poco::PROCESS_CLOSE_STDERR;
- /// Constant to prevent std out and err from being received from the process.
- ProcessRunner(const std::string& cmd,
- const Args& args,
- const std::string& pidFile = "",
- int options = NO_OUT,
- int timeout = 10, /*seconds*/
- bool startProcess = true,
- const Args& pidArgFmt = pidArgFormat());
- /// Creates the ProcessRunner.
- ///
- /// If `pidFile` is not empty, the starting of the process waits
- /// until the pid file has been updated with the new pid, and
- /// the stopping of the process waits until the pid file is gone.
- /// Waiting is terminated after timeout seconds.
- ///
- /// If `pidFile` is empty and `pidArgFmt` is not empty, autodetect
- /// of PID file from `args` is attempted; the default PID file
- /// argument format corresponds to the one used by
- /// `Poco::Util::Application`
- ///
- /// The `options` are passed to the process, defaulting to
- /// closed stdio output pipes.
- ///
- /// The `timeout` in seconds determines how long the ProcessRunner
- /// waits for the process to start; if PID file name is provided or
- /// autodetected from arguments, ProcessRunner will wait until the file
- /// exists and contains the process PID or timeout expires (in which
- /// case a TimeoutException is thrown).
- ///
- /// If `startProcess` is true, the process is started on object creation.
- ~ProcessRunner();
- /// Destroys the ProcessRunner.
- PID pid() const;
- /// Returns the process PID.
- const std::string& pidFile() const;
- /// Returns the process PID filename.
- /// Returns empty string when pid filename
- /// is not specified at construction, either
- /// explicitly, or implicitly through
- /// command line argument.
- bool running() const;
- /// Returns true if process is running.
- void start();
- /// Starts the process and waits for it to be fully initialized.
- /// Process initialization completion is indicated by a new pid in
- /// the pid file (if specified at construction, otherwise there
- /// is no wating for pid).
- /// If pid file is not specified, there is no waiting.
- ///
- /// Attempting to start a started process results in
- /// Poco::InvalidAccessException being thrown.
- void stop();
- /// Stops the process.
- ///
- /// Calling stop() on a stopped process is a no-op.
- std::string cmdLine() const;
- /// Returns process full command line.
- int result() const;
- /// Returns process return code.
- int runCount() const;
- /// Returns the number of times the process has been executed.
- private:
- static const Poco::ProcessHandle::PID INVALID_PID = -1;
- static const int RESULT_UNKNOWN = -1;
- static Args pidArgFormat()
- {
- #if defined(POCO_OS_FAMILY_WINDOWS)
- return Args{"-p", "--pidfile=", "/p", "/pidfile="};
- #else
- return Args{"-p", "--pidfile="};
- #endif
- }
- void run();
- /// Starts the process and waits for it to be fully initialized.
- /// Process initialization completion is indicated by new pid in
- /// the pid file. If pid file is not specified, there is no waiting.
- void checkTimeout(const Poco::Stopwatch& sw, const std::string& msg);
- /// If timeout is exceeded, throws TimeoutException with `msg`
- /// message.
- Poco::Thread _t;
- std::string _cmd;
- Args _args;
- std::atomic<PID> _pid;
- std::string _pidFile;
- int _options;
- int _timeout;
- std::atomic<Poco::ProcessHandle*> _pPH;
- std::atomic<bool> _started;
- std::atomic<int> _rc;
- std::atomic<int> _runCount;
- };
- //
- // inlines
- //
- inline const std::string& ProcessRunner::pidFile() const
- {
- return _pidFile;
- }
- inline bool ProcessRunner::running() const
- {
- return _pid != INVALID_PID;
- }
- inline ProcessRunner::PID ProcessRunner::pid() const
- {
- return _pid;
- }
- inline int ProcessRunner::result() const
- {
- return _rc;
- }
- inline int ProcessRunner::runCount() const
- {
- return _runCount;
- }
- } // namespace Poco
- #endif // Foundation_ProcessRunner_INCLUDED
|