aboutsummaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/SubProcess.cpp131
-rw-r--r--src/common/platform/unix/PosixSpawnSubProcess.cpp24
2 files changed, 141 insertions, 14 deletions
diff --git a/src/common/SubProcess.cpp b/src/common/SubProcess.cpp
index 69f52d9c..0ffb2387 100644
--- a/src/common/SubProcess.cpp
+++ b/src/common/SubProcess.cpp
@@ -1,5 +1,7 @@
#include "cru/common/SubProcess.h"
+#include <thread>
+
#ifdef CRU_PLATFORM_UNIX
#include "cru/common/platform/unix/PosixSpawnSubProcess.h"
#endif
@@ -7,9 +9,133 @@
namespace cru {
#ifdef CRU_PLATFORM_UNIX
-using ThisPlatformSubProcess = platform::unix::PosixSpawnSubProcess;
+using ThisPlatformSubProcessImpl = platform::unix::PosixSpawnSubProcessImpl;
#endif
+PlatformSubProcess::PlatformSubProcess(
+ SubProcessStartInfo start_info,
+ std::shared_ptr<IPlatformSubProcessImpl> impl)
+ : state_(new State(std::move(start_info), std::move(impl))) {}
+
+PlatformSubProcess::~PlatformSubProcess() {}
+
+void PlatformSubProcess::Start() {
+ std::lock_guard lock_guard(this->state_->lock);
+
+ if (this->state_->status != SubProcessStatus::Prepare) {
+ throw SubProcessException(u"The process has already tried to start.");
+ }
+
+ try {
+ this->state_->impl->PlatformCreateProcess(this->state_->start_info);
+ this->state_->status = SubProcessStatus::Running;
+
+ auto thread = std::thread([state = state_] {
+ std::lock_guard lock_guard(state->lock);
+ state->exit_result = state->impl->PlatformWaitForProcess();
+ state->status = SubProcessStatus::Exited;
+ state->condition_variable.notify_all();
+ });
+
+ thread.detach();
+ } catch (const std::exception& e) {
+ this->state_->status = SubProcessStatus::FailedToStart;
+ throw SubProcessFailedToStartException(u"Sub-process failed to start. " +
+ String::FromUtf8(e.what()));
+ }
+}
+
+void PlatformSubProcess::Wait(
+ std::optional<std::chrono::milliseconds> wait_time) {
+ std::lock_guard lock_guard(this->state_->lock);
+
+ if (this->state_->status == SubProcessStatus::Prepare) {
+ throw SubProcessException(
+ u"The process does not start. Can't wait for it.");
+ }
+
+ if (this->state_->status == SubProcessStatus::FailedToStart) {
+ throw SubProcessException(
+ u"The process failed to start. Can't wait for it.");
+ }
+
+ if (this->state_->status == SubProcessStatus::Exited) {
+ return;
+ }
+
+ auto predicate = [this] {
+ return this->state_->status == SubProcessStatus::Exited;
+ };
+
+ if (wait_time) {
+ this->state_->condition_variable.wait_for(this->state_->lock, *wait_time,
+ predicate);
+ } else {
+ this->state_->condition_variable.wait(this->state_->lock, predicate);
+ }
+}
+
+void PlatformSubProcess::Kill() {
+ std::lock_guard lock_guard(this->state_->lock);
+
+ if (this->state_->status == SubProcessStatus::Prepare) {
+ throw SubProcessException(u"The process does not start. Can't kill it.");
+ }
+
+ if (this->state_->status == SubProcessStatus::FailedToStart) {
+ throw SubProcessException(u"The process failed to start. Can't kill it.");
+ }
+
+ if (this->state_->status == SubProcessStatus::Exited) {
+ return;
+ }
+
+ if (this->state_->killed) {
+ return;
+ }
+
+ this->state_->impl->PlatformKillProcess();
+ this->state_->killed = true;
+}
+
+SubProcessStatus PlatformSubProcess::GetStatus() {
+ std::lock_guard lock_guard(this->state_->lock);
+ return this->state_->status;
+}
+
+SubProcessExitResult PlatformSubProcess::GetExitResult() {
+ std::lock_guard lock_guard(this->state_->lock);
+
+ if (this->state_->status == SubProcessStatus::Prepare) {
+ throw SubProcessException(
+ u"The process does not start. Can't get exit result.");
+ }
+
+ if (this->state_->status == SubProcessStatus::FailedToStart) {
+ throw SubProcessException(
+ u"The process failed to start. Can't get exit result.");
+ }
+
+ if (this->state_->status == SubProcessStatus::Running) {
+ throw SubProcessException(
+ u"The process is running. Can't get exit result.");
+ }
+
+ return this->state_->exit_result;
+}
+
+io::Stream* PlatformSubProcess::GetStdinStream() {
+ return this->state_->impl->GetStdinStream();
+}
+
+io::Stream* PlatformSubProcess::GetStdoutStream() {
+ return this->state_->impl->GetStdoutStream();
+}
+
+io::Stream* PlatformSubProcess::GetStderrStream() {
+ return this->state_->impl->GetStderrStream();
+}
+
SubProcess SubProcess::Create(String program, std::vector<String> arguments,
std::unordered_map<String, String> environments) {
SubProcessStartInfo start_info;
@@ -20,7 +146,8 @@ SubProcess SubProcess::Create(String program, std::vector<String> arguments,
}
SubProcess::SubProcess(SubProcessStartInfo start_info) {
- platform_process_.reset(new ThisPlatformSubProcess(std::move(start_info)));
+ platform_process_.reset(new PlatformSubProcess(
+ std::move(start_info), std::make_shared<ThisPlatformSubProcessImpl>()));
platform_process_->Start();
}
diff --git a/src/common/platform/unix/PosixSpawnSubProcess.cpp b/src/common/platform/unix/PosixSpawnSubProcess.cpp
index 1e2a84d6..8b521a5e 100644
--- a/src/common/platform/unix/PosixSpawnSubProcess.cpp
+++ b/src/common/platform/unix/PosixSpawnSubProcess.cpp
@@ -35,18 +35,6 @@ PosixSpawnSubProcessImpl::PosixSpawnSubProcessImpl()
PosixSpawnSubProcessImpl::~PosixSpawnSubProcessImpl() {}
-io::Stream* PosixSpawnSubProcessImpl::GetStdinStream() {
- return stdin_stream_.get();
-}
-
-io::Stream* PosixSpawnSubProcessImpl::GetStdoutStream() {
- return stdout_buffer_stream_.get();
-}
-
-io::Stream* PosixSpawnSubProcessImpl::GetStderrStream() {
- return stderr_buffer_stream_.get();
-}
-
namespace {
char** CreateCstrArray(const std::vector<String>& argv) {
std::vector<Buffer> utf8_argv;
@@ -181,4 +169,16 @@ void PosixSpawnSubProcessImpl::PlatformKillProcess() {
std::move(inner));
}
}
+
+io::Stream* PosixSpawnSubProcessImpl::GetStdinStream() {
+ return stdin_stream_.get();
+}
+
+io::Stream* PosixSpawnSubProcessImpl::GetStdoutStream() {
+ return stdout_buffer_stream_.get();
+}
+
+io::Stream* PosixSpawnSubProcessImpl::GetStderrStream() {
+ return stderr_buffer_stream_.get();
+}
} // namespace cru::platform::unix