diff options
Diffstat (limited to 'include/cru/common/SubProcess.h')
-rw-r--r-- | include/cru/common/SubProcess.h | 87 |
1 files changed, 68 insertions, 19 deletions
diff --git a/include/cru/common/SubProcess.h b/include/cru/common/SubProcess.h index 0e05fd5a..6a3cc6e6 100644 --- a/include/cru/common/SubProcess.h +++ b/include/cru/common/SubProcess.h @@ -19,7 +19,7 @@ enum class PlatformSubProcessStatus { /** * @brief The process is failed to start. */ - FailToStart, + FailedToStart, /** * @brief The process is running now. */ @@ -42,9 +42,16 @@ struct PlatformSubProcessStartInfo { std::vector<String> environments; }; +struct PlatformSubProcessExitResult { + int exit_code; +}; + /** * @brief Base class of a platform process. It is one-time, which means it * starts and exits and can't start again. + * @remarks + * If an object of this class is destructed before the process ends, the process + * will be killed. */ class PlatformSubProcessBase : public Object { public: @@ -55,21 +62,59 @@ class PlatformSubProcessBase : public Object { /** * @brief Create and start a real process. If the program can't be created or - * start, an exception should be thrown. + * start, an exception will be thrown. + * + * @remarks This method will hold the data lock during running. It ensures + * after return, the process already tries to start and status is definitely + * not `Prepare` but `FailedToStart` or `Running` or `Exit`. So it is safe to + * use `GetStatus` to check whether the process tries to start, aka, this + * method has been called or not. */ void Start(); + /** - * @brief Wait for the process to exit for at most `wait_time`. + * @brief Wait for the process to exit for at most `wait_time`. If the process + * already exits, it will return immediately. If the process has not started + * or failed to start, it will throw. Ensure `Start` is called and does not + * throw before call this. + * + * @remarks You may wish this returns bool to indicate whether it is timeout + * or the process exits. But no, even if it is timeout, the process may also + * exits due to task schedule. */ void Wait(std::optional<std::chrono::milliseconds> wait_time); - PlatformSubProcessStatus GetStatus() const; - int GetExitCode() const; + + /** + * @brief kill the process if it is running. If the process already exits, + * nothing will happen. If the process has not started or failed to start, it + * will throw. Ensure `Start` is called and does not throw before call this. + */ + void Kill(); + + /** + * @brief Get the status of the process. + * 1. If the process has tried to start, aka `Start` is called, then this + * method must return `Running`, `FailedToStart`. + * 2. If it returns `Prepare`, `Start` is not called. + * 3. It does NOT guarantee that this return `Running` and the process is + * actually running. Because there might be a window that the process exits + * already but status is not updated. + */ + PlatformSubProcessStatus GetStatus(); + + PlatformSubProcessExitResult GetExitResult(); io::Stream* GetStdinStream(); io::Stream* GetStdoutStream(); io::Stream* GetStderrStream(); - void Join(); - void Detach(); + bool IsAutoDeleteAfterProcessExit() const; + + /** + * @brief If auto delete, this instance will delete it self after the process + * exits. The delete will be called at another thread. You must ensure this + * object is created by new. + */ + void SetAutoDeleteAfterProcessExit(bool auto_delete); protected: /** @@ -84,16 +129,26 @@ class PlatformSubProcessBase : public Object { virtual void PlatformCreateProcess() = 0; /** - * @brief Wait for the created process forever. After process exits, fill the - * result info of internal data. + * @brief Wait for the created process forever. * - * Implementation should wait for the real process forever. + * Implementation should wait for the real process forever, after that, fill + * internal data and returns exit result. * - * This method will be called on another thread. It will only called once + * This method will be called on another thread. It will only be 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; + virtual PlatformSubProcessExitResult PlatformWaitForProcess() = 0; + + /** + * @brief Kill the process immediately. + * + * This method will be called on this thread. It will only be called once + * after a success call of `Start`. There will be a window that the window + * already exits but the status has not been updated and this is called. So + * handle this gracefully and write to internal data carefully. + */ + virtual void PlatformKillProcess() = 0; private: auto CreateDataLockGuard() { @@ -108,13 +163,7 @@ class PlatformSubProcessBase : public Object { PlatformSubProcessStartInfo start_info_; private: - enum class DisposeKind { - None, - Join, - Detach, - }; - - DisposeKind dispose_; + bool auto_delete_; PlatformSubProcessStatus status_; |