aboutsummaryrefslogtreecommitdiff
path: root/include/cru/common/SubProcess.h
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2024-10-06 13:57:39 +0800
committercrupest <crupest@outlook.com>2024-10-06 13:57:39 +0800
commitdfe62dcf8bcefc523b466e127c3edc4dc2756629 (patch)
tree1c751a14ba0da07ca2ff805633f97568060aa4c9 /include/cru/common/SubProcess.h
parentf51eb955e188858272230a990565931e7403f23b (diff)
downloadcru-dfe62dcf8bcefc523b466e127c3edc4dc2756629.tar.gz
cru-dfe62dcf8bcefc523b466e127c3edc4dc2756629.tar.bz2
cru-dfe62dcf8bcefc523b466e127c3edc4dc2756629.zip
Rename common to base.
Diffstat (limited to 'include/cru/common/SubProcess.h')
-rw-r--r--include/cru/common/SubProcess.h258
1 files changed, 0 insertions, 258 deletions
diff --git a/include/cru/common/SubProcess.h b/include/cru/common/SubProcess.h
deleted file mode 100644
index fbe8ad2b..00000000
--- a/include/cru/common/SubProcess.h
+++ /dev/null
@@ -1,258 +0,0 @@
-#pragma once
-#include "Base.h"
-#include "Exception.h"
-#include "String.h"
-#include "io/Stream.h"
-
-#include <chrono>
-#include <condition_variable>
-#include <mutex>
-#include <optional>
-#include <unordered_map>
-#include <vector>
-
-namespace cru {
-enum class SubProcessStatus {
- /**
- * @brief The process has not been created and started.
- */
- Prepare,
- /**
- * @brief The process is failed to start.
- */
- FailedToStart,
- /**
- * @brief The process is running now.
- */
- Running,
- /**
- * @brief The process has been exited.
- */
- Exited,
-};
-
-class CRU_BASE_API SubProcessException : public Exception {
- public:
- using Exception::Exception;
-};
-
-class CRU_BASE_API SubProcessFailedToStartException
- : public SubProcessException {
- public:
- using SubProcessException::SubProcessException;
-};
-
-class CRU_BASE_API SubProcessInternalException : public SubProcessException {
- public:
- using SubProcessException::SubProcessException;
-};
-
-struct SubProcessStartInfo {
- String program;
- std::vector<String> arguments;
- std::unordered_map<String, String> environments;
-};
-
-enum class SubProcessExitType {
- Unknown,
- Normal,
- Signal,
-};
-
-struct SubProcessExitResult {
- SubProcessExitType exit_type;
- int exit_code;
- int exit_signal;
- bool has_core_dump;
-
- bool IsSuccess() const {
- return exit_type == SubProcessExitType::Normal && exit_code == 0;
- }
-
- static SubProcessExitResult Unknown() {
- return {SubProcessExitType::Unknown, 0, 0, false};
- }
-
- static SubProcessExitResult Normal(int exit_code) {
- return {SubProcessExitType::Normal, exit_code, 0, false};
- }
-
- static SubProcessExitResult Signal(int exit_signal, bool has_core_dump) {
- return {SubProcessExitType::Normal, 0, exit_signal, has_core_dump};
- }
-};
-
-struct IPlatformSubProcessImpl : virtual Interface {
- /**
- * @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 only once in first call of `Start` on this
- * thread with lock holdDefaultConstructible.
- */
- virtual void PlatformCreateProcess(const SubProcessStartInfo& start_info) = 0;
-
- /**
- * @brief Wait for the created process forever and return the exit result
- * when process stops.
- *
- * Implementation should wait for the real process forever, after that,
- * fill internal data and returns exit result.
- *
- * This method will be called only once on another thread after
- * `PlatformCreateProcess` returns successfully
- */
- virtual SubProcessExitResult PlatformWaitForProcess() = 0;
-
- /**
- * @brief Kill the process immediately.
- *
- * This method will be called only once on this thread given
- * `PlatformCreateProcess` returns successfully. 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;
-
- virtual io::Stream* GetStdinStream() = 0;
- virtual io::Stream* GetStdoutStream() = 0;
- virtual io::Stream* GetStderrStream() = 0;
-};
-
-/**
- * @brief A wrapper platform process. It is one-time, which means it
- * starts and exits and can't start again.
- *
- * TODO: Current implementation has a problem. If the process does not exit for
- * a long time, the resource related to it will not be released. It may cause a
- * leak.
- */
-class PlatformSubProcess : public Object {
- CRU_DEFINE_CLASS_LOG_TAG(u"PlatformSubProcess")
-
- private:
- struct State {
- explicit State(SubProcessStartInfo start_info,
- std::shared_ptr<IPlatformSubProcessImpl> impl)
- : start_info(std::move(start_info)), impl(std::move(impl)) {}
-
- std::mutex mutex;
- std::condition_variable condition_variable;
- SubProcessStartInfo start_info;
- SubProcessExitResult exit_result;
- SubProcessStatus status = SubProcessStatus::Prepare;
- bool killed = false;
- std::shared_ptr<IPlatformSubProcessImpl> impl;
- };
-
- public:
- PlatformSubProcess(SubProcessStartInfo start_info,
- std::shared_ptr<IPlatformSubProcessImpl> impl);
-
- ~PlatformSubProcess() override;
-
- /**
- * @brief Create and start a real process. If the process can't be created or
- * start, `SubProcessFailedToStartException` will be thrown. If this function
- * is already called once, `SubProcessException` will be thrown. Ensure only
- * call this method once.
- */
- void Start();
-
- /**
- * @brief Wait for the process to exit optionally for at most `wait_time`. If
- * the process already exits, it will return immediately. If the process has
- * not started or failed to start, `SubProcessException` will be thrown.
- * Ensure `Start` is called and does not throw before calling 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
- * have exited due to task schedule.
- */
- void Wait(std::optional<std::chrono::milliseconds> wait_time);
-
- /**
- * @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,
- * `SubProcessException` will be throw. Ensure `Start` is called and does not
- * throw before calling 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 will return one of `Running`, `FailedToStart`, `Exited`.
- * 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.
- */
- SubProcessStatus GetStatus();
-
- /**
- * @brief Get the exit result. If the process is not started, failed to start
- * or running, `SubProcessException` will be thrown.
- */
- SubProcessExitResult GetExitResult();
-
- io::Stream* GetStdinStream();
- io::Stream* GetStdoutStream();
- io::Stream* GetStderrStream();
-
- private:
- std::shared_ptr<State> state_;
- std::unique_lock<std::mutex> lock_;
-};
-
-class CRU_BASE_API SubProcess : public Object {
- CRU_DEFINE_CLASS_LOG_TAG(u"SubProcess")
-
- public:
- static SubProcess Create(
- String program, std::vector<String> arguments = {},
- std::unordered_map<String, String> environments = {});
-
- static SubProcessExitResult Call(
- String program, std::vector<String> arguments = {},
- std::unordered_map<String, String> environments = {});
-
- public:
- SubProcess(SubProcessStartInfo start_info);
-
- CRU_DELETE_COPY(SubProcess)
-
- SubProcess(SubProcess&& other) = default;
- SubProcess& operator=(SubProcess&& other) = default;
-
- ~SubProcess() override;
-
- public:
- void Wait(std::optional<std::chrono::milliseconds> wait_time = std::nullopt);
- void Kill();
-
- SubProcessStatus GetStatus();
- SubProcessExitResult GetExitResult();
-
- io::Stream* GetStdinStream();
- io::Stream* GetStdoutStream();
- io::Stream* GetStderrStream();
-
- void Detach();
-
- bool IsValid() const { return platform_process_ != nullptr; }
- explicit operator bool() const { return IsValid(); }
-
- private:
- void CheckValid() const;
-
- private:
- std::unique_ptr<PlatformSubProcess> platform_process_;
-};
-} // namespace cru