ProcessRunner.h 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. //
  2. // ProcessRunner.h
  3. //
  4. // Library: Foundation
  5. // Package: Processes
  6. // Module: ProcessRunner
  7. //
  8. // Definition of the ProcessRunner class.
  9. //
  10. // Copyright (c) 2023, Applied Informatics Software Engineering GmbH.
  11. // Aleph ONE Software Engineering d.o.o.,
  12. // and Contributors.
  13. //
  14. // SPDX-License-Identifier: BSL-1.0
  15. //
  16. #ifndef Foundation_ProcessRunner_INCLUDED
  17. #define Foundation_ProcessRunner_INCLUDED
  18. #include "Poco/Foundation.h"
  19. #include "Poco/Process.h"
  20. #include "Poco/ProcessOptions.h"
  21. #include "Poco/Runnable.h"
  22. #include "Poco/Thread.h"
  23. #include "Poco/Format.h"
  24. #include "Poco/Stopwatch.h"
  25. #include <atomic>
  26. #include <vector>
  27. namespace Poco {
  28. class Foundation_API ProcessRunner: public Poco::Runnable
  29. /// ProcessRunner is a wrapper class for `Poco::ProcessHandle.
  30. /// It starts and terminates a process with enabled or disabled (default)
  31. /// `stdio` pipes, and optionally waits for process PID to be created before
  32. /// returning control to the caller. The process is spawned from an
  33. /// internal thread. Starting/stopping the process may block up to
  34. /// a certain (configurable) period of time.
  35. ///
  36. /// ProcessRunner can hold and control only one process at a time, which
  37. /// can be started/stopped multiple times during the ProcessRunner lifetime.
  38. {
  39. public:
  40. using Args = Poco::Process::Args;
  41. using PID = Poco::ProcessHandle::PID;
  42. static const int NO_OUT = Poco::PROCESS_CLOSE_STDOUT|Poco::PROCESS_CLOSE_STDERR;
  43. /// Constant to prevent std out and err from being received from the process.
  44. ProcessRunner(const std::string& cmd,
  45. const Args& args,
  46. const std::string& pidFile = "",
  47. int options = NO_OUT,
  48. int timeout = 10, /*seconds*/
  49. bool startProcess = true,
  50. const Args& pidArgFmt = pidArgFormat());
  51. /// Creates the ProcessRunner.
  52. ///
  53. /// If `pidFile` is not empty, the starting of the process waits
  54. /// until the pid file has been updated with the new pid, and
  55. /// the stopping of the process waits until the pid file is gone.
  56. /// Waiting is terminated after timeout seconds.
  57. ///
  58. /// If `pidFile` is empty and `pidArgFmt` is not empty, autodetect
  59. /// of PID file from `args` is attempted; the default PID file
  60. /// argument format corresponds to the one used by
  61. /// `Poco::Util::Application`
  62. ///
  63. /// The `options` are passed to the process, defaulting to
  64. /// closed stdio output pipes.
  65. ///
  66. /// The `timeout` in seconds determines how long the ProcessRunner
  67. /// waits for the process to start; if PID file name is provided or
  68. /// autodetected from arguments, ProcessRunner will wait until the file
  69. /// exists and contains the process PID or timeout expires (in which
  70. /// case a TimeoutException is thrown).
  71. ///
  72. /// If `startProcess` is true, the process is started on object creation.
  73. ~ProcessRunner();
  74. /// Destroys the ProcessRunner.
  75. PID pid() const;
  76. /// Returns the process PID.
  77. const std::string& pidFile() const;
  78. /// Returns the process PID filename.
  79. /// Returns empty string when pid filename
  80. /// is not specified at construction, either
  81. /// explicitly, or implicitly through
  82. /// command line argument.
  83. bool running() const;
  84. /// Returns true if process is running.
  85. void start();
  86. /// Starts the process and waits for it to be fully initialized.
  87. /// Process initialization completion is indicated by a new pid in
  88. /// the pid file (if specified at construction, otherwise there
  89. /// is no wating for pid).
  90. /// If pid file is not specified, there is no waiting.
  91. ///
  92. /// Attempting to start a started process results in
  93. /// Poco::InvalidAccessException being thrown.
  94. void stop();
  95. /// Stops the process.
  96. ///
  97. /// Calling stop() on a stopped process is a no-op.
  98. std::string cmdLine() const;
  99. /// Returns process full command line.
  100. int result() const;
  101. /// Returns process return code.
  102. int runCount() const;
  103. /// Returns the number of times the process has been executed.
  104. private:
  105. static const Poco::ProcessHandle::PID INVALID_PID = -1;
  106. static const int RESULT_UNKNOWN = -1;
  107. static Args pidArgFormat()
  108. {
  109. #if defined(POCO_OS_FAMILY_WINDOWS)
  110. return Args{"-p", "--pidfile=", "/p", "/pidfile="};
  111. #else
  112. return Args{"-p", "--pidfile="};
  113. #endif
  114. }
  115. void run();
  116. /// Starts the process and waits for it to be fully initialized.
  117. /// Process initialization completion is indicated by new pid in
  118. /// the pid file. If pid file is not specified, there is no waiting.
  119. void checkTimeout(const Poco::Stopwatch& sw, const std::string& msg);
  120. /// If timeout is exceeded, throws TimeoutException with `msg`
  121. /// message.
  122. Poco::Thread _t;
  123. std::string _cmd;
  124. Args _args;
  125. std::atomic<PID> _pid;
  126. std::string _pidFile;
  127. int _options;
  128. int _timeout;
  129. std::atomic<Poco::ProcessHandle*> _pPH;
  130. std::atomic<bool> _started;
  131. std::atomic<int> _rc;
  132. std::atomic<int> _runCount;
  133. };
  134. //
  135. // inlines
  136. //
  137. inline const std::string& ProcessRunner::pidFile() const
  138. {
  139. return _pidFile;
  140. }
  141. inline bool ProcessRunner::running() const
  142. {
  143. return _pid != INVALID_PID;
  144. }
  145. inline ProcessRunner::PID ProcessRunner::pid() const
  146. {
  147. return _pid;
  148. }
  149. inline int ProcessRunner::result() const
  150. {
  151. return _rc;
  152. }
  153. inline int ProcessRunner::runCount() const
  154. {
  155. return _runCount;
  156. }
  157. } // namespace Poco
  158. #endif // Foundation_ProcessRunner_INCLUDED