diff options
author | crupest <crupest@outlook.com> | 2024-06-24 00:06:25 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2024-07-21 13:45:23 +0800 |
commit | 5f0d7dc36a7a0091bfc152be9f06730cd08eb4dd (patch) | |
tree | 72ded26e72272dc2f7edf29146b907e52784ad6a /src/common/SubProcess.cpp | |
parent | e532469ca8844bf4daff8d462f80abdd776c018f (diff) | |
download | cru-5f0d7dc36a7a0091bfc152be9f06730cd08eb4dd.tar.gz cru-5f0d7dc36a7a0091bfc152be9f06730cd08eb4dd.tar.bz2 cru-5f0d7dc36a7a0091bfc152be9f06730cd08eb4dd.zip |
feat: reimplement subprocess without template.
NEED TEST: BufferStream, AutoReadStream, SubProcess.
Diffstat (limited to 'src/common/SubProcess.cpp')
-rw-r--r-- | src/common/SubProcess.cpp | 131 |
1 files changed, 129 insertions, 2 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(); } |