diff options
Diffstat (limited to 'include/cru')
-rw-r--r-- | include/cru/common/SubProcess.h | 109 | ||||
-rw-r--r-- | include/cru/common/io/Stream.h | 2 | ||||
-rw-r--r-- | include/cru/common/platform/unix/PosixSpawnSubProcess.h | 23 |
3 files changed, 126 insertions, 8 deletions
diff --git a/include/cru/common/SubProcess.h b/include/cru/common/SubProcess.h index 341afc5c..0e05fd5a 100644 --- a/include/cru/common/SubProcess.h +++ b/include/cru/common/SubProcess.h @@ -1,9 +1,13 @@ #pragma once #include "Base.h" +#include "Exception.h" #include "String.h" +#include "io/Stream.h" #include <chrono> +#include <mutex> #include <optional> +#include <thread> #include <vector> namespace cru { @@ -13,6 +17,10 @@ enum class PlatformSubProcessStatus { */ Prepare, /** + * @brief The process is failed to start. + */ + FailToStart, + /** * @brief The process is running now. */ Running, @@ -22,20 +30,107 @@ enum class PlatformSubProcessStatus { Exited, }; +class CRU_BASE_API SubProcessException : public Exception { + public: + SubProcessException(String message = {}); + ~SubProcessException() override; +}; + +struct PlatformSubProcessStartInfo { + String program; + std::vector<String> arguments; + std::vector<String> environments; +}; + /** - * Interface of a platform process. It is one-time, which means it starts and - * exits and can't start again. + * @brief Base class of a platform process. It is one-time, which means it + * starts and exits and can't start again. */ -struct IPlatformSubProcess : virtual Interface { +class PlatformSubProcessBase : public Object { + public: + explicit PlatformSubProcessBase( + const PlatformSubProcessStartInfo& start_info); + + ~PlatformSubProcessBase() override; + + /** + * @brief Create and start a real process. If the program can't be created or + * start, an exception should be thrown. + */ + void Start(); /** - * Create and start a real process. + * @brief Wait for the process to exit for at most `wait_time`. */ - void Start(String program, std::vector<String> arguments, - std::vector<String> environments); void Wait(std::optional<std::chrono::milliseconds> wait_time); - void Reap(); PlatformSubProcessStatus GetStatus() const; int GetExitCode() const; + io::Stream* GetStdinStream(); + io::Stream* GetStdoutStream(); + io::Stream* GetStderrStream(); + + void Join(); + void Detach(); + + protected: + /** + * @brief Create and start a real process. If the program can't be created or + * start, an exception should be thrown. + * + * Implementation should fill internal data of the new process and start it. + * + * This method will be called on this thread with data lock hold. It will only + * called once in first call of `Start`. + */ + virtual void PlatformCreateProcess() = 0; + + /** + * @brief Wait for the created process forever. After process exits, fill the + * result info of internal data. + * + * Implementation should wait for the real process forever. + * + * This method will be called on another thread. It will only called once + * after a success call of `Start`. It is safe to write internal data in this + * method because process lock will be hold and we won't write to internal. + */ + virtual void PlatformWaitForProcess() = 0; + + private: + auto CreateDataLockGuard() { + return std::lock_guard<std::unique_lock<std::mutex>>(data_lock_); + } + + auto CreateProcessLockGuard() { + return std::lock_guard<std::unique_lock<std::timed_mutex>>(process_lock_); + } + + protected: + PlatformSubProcessStartInfo start_info_; + + private: + enum class DisposeKind { + None, + Join, + Detach, + }; + + DisposeKind dispose_; + + PlatformSubProcessStatus status_; + + std::mutex data_mutex_; + /** + * Lock for protecting data of this class. + */ + std::unique_lock<std::mutex> data_lock_; + std::thread process_thread_; + + std::timed_mutex process_mutex_; + /** + * Lock for protecting internal data of sub-class, and used for detect whether + * process is running. + */ + std::unique_lock<std::timed_mutex> process_lock_; }; class CRU_BASE_API SubProcess : public Object { diff --git a/include/cru/common/io/Stream.h b/include/cru/common/io/Stream.h index d24931da..b8e324d1 100644 --- a/include/cru/common/io/Stream.h +++ b/include/cru/common/io/Stream.h @@ -32,7 +32,7 @@ class CRU_BASE_API StreamOperationNotSupportedException : public Exception { class CRU_BASE_API StreamAlreadyClosedException : public Exception { public: - StreamAlreadyClosedException(); + StreamAlreadyClosedException(); CRU_DEFAULT_COPY(StreamAlreadyClosedException) CRU_DEFAULT_MOVE(StreamAlreadyClosedException) diff --git a/include/cru/common/platform/unix/PosixSpawnSubProcess.h b/include/cru/common/platform/unix/PosixSpawnSubProcess.h new file mode 100644 index 00000000..02b9e7e2 --- /dev/null +++ b/include/cru/common/platform/unix/PosixSpawnSubProcess.h @@ -0,0 +1,23 @@ +#pragma once + +#include "../../PreConfig.h" + +#ifdef CRU_PLATFORM_UNIX + +#include "../../SubProcess.h" + +#include <spawn.h> + +namespace cru::platform::unix { +class PosixSpawnSubProcess : public PlatformSubProcessBase { + public: + explicit PosixSpawnSubProcess(const PlatformSubProcessStartInfo& start_info); + ~PosixSpawnSubProcess(); + + private: + pid_t pid_; + int exit_code_; +}; +} // namespace cru::platform::unix + +#endif |