From 211b80abe252a46a98df8a9a3efb036041c6526d Mon Sep 17 00:00:00 2001 From: crupest Date: Sat, 16 Dec 2023 23:55:49 +0800 Subject: Add PlatformSubProcessBase. --- include/cru/common/SubProcess.h | 109 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 102 insertions(+), 7 deletions(-) (limited to 'include/cru/common/SubProcess.h') 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 +#include #include +#include #include namespace cru { @@ -12,6 +16,10 @@ enum class PlatformSubProcessStatus { * @brief The process has not been created and started. */ Prepare, + /** + * @brief The process is failed to start. + */ + FailToStart, /** * @brief The process is running now. */ @@ -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 arguments; + std::vector 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 arguments, - std::vector environments); void Wait(std::optional 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>(data_lock_); + } + + auto CreateProcessLockGuard() { + return std::lock_guard>(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 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 process_lock_; }; class CRU_BASE_API SubProcess : public Object { -- cgit v1.2.3