aboutsummaryrefslogtreecommitdiff
path: root/include/cru
diff options
context:
space:
mode:
Diffstat (limited to 'include/cru')
-rw-r--r--include/cru/common/SubProcess.h109
-rw-r--r--include/cru/common/io/Stream.h2
-rw-r--r--include/cru/common/platform/unix/PosixSpawnSubProcess.h23
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