aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2024-06-24 00:06:25 +0800
committercrupest <crupest@outlook.com>2024-07-21 22:33:50 +0800
commit1e8bb0de0b0b05dc1323520dfa57df1f19b51b83 (patch)
tree225bfbf13ecf1a97e2573c174ee867f7301186be
parent5f0d7dc36a7a0091bfc152be9f06730cd08eb4dd (diff)
downloadcru-1e8bb0de0b0b05dc1323520dfa57df1f19b51b83.tar.gz
cru-1e8bb0de0b0b05dc1323520dfa57df1f19b51b83.tar.bz2
cru-1e8bb0de0b0b05dc1323520dfa57df1f19b51b83.zip
fix: a lock bug and add test for Wait.
NEED TEST: BufferStream, AutoReadStream, SubProcess.
-rw-r--r--include/cru/common/SubProcess.h10
-rw-r--r--src/common/SubProcess.cpp28
-rw-r--r--test/common/SubProcessTest.cpp2
3 files changed, 30 insertions, 10 deletions
diff --git a/include/cru/common/SubProcess.h b/include/cru/common/SubProcess.h
index 078d5546..98c272a3 100644
--- a/include/cru/common/SubProcess.h
+++ b/include/cru/common/SubProcess.h
@@ -65,6 +65,10 @@ struct SubProcessExitResult {
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};
}
@@ -139,7 +143,6 @@ class PlatformSubProcess : public Object {
: start_info(std::move(start_info)), impl(std::move(impl)) {}
std::mutex mutex;
- std::unique_lock<std::mutex> lock{mutex, std::defer_lock};
std::condition_variable condition_variable;
SubProcessStartInfo start_info;
SubProcessExitResult exit_result;
@@ -205,6 +208,7 @@ class PlatformSubProcess : public Object {
private:
std::shared_ptr<State> state_;
+ std::unique_lock<std::mutex> lock_;
};
class CRU_BASE_API SubProcess : public Object {
@@ -215,6 +219,10 @@ class CRU_BASE_API SubProcess : public Object {
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);
diff --git a/src/common/SubProcess.cpp b/src/common/SubProcess.cpp
index 0ffb2387..33926f39 100644
--- a/src/common/SubProcess.cpp
+++ b/src/common/SubProcess.cpp
@@ -15,12 +15,13 @@ using ThisPlatformSubProcessImpl = platform::unix::PosixSpawnSubProcessImpl;
PlatformSubProcess::PlatformSubProcess(
SubProcessStartInfo start_info,
std::shared_ptr<IPlatformSubProcessImpl> impl)
- : state_(new State(std::move(start_info), std::move(impl))) {}
+ : state_(new State(std::move(start_info), std::move(impl))),
+ lock_(state_->mutex, std::defer_lock) {}
PlatformSubProcess::~PlatformSubProcess() {}
void PlatformSubProcess::Start() {
- std::lock_guard lock_guard(this->state_->lock);
+ std::lock_guard lock_guard(this->lock_);
if (this->state_->status != SubProcessStatus::Prepare) {
throw SubProcessException(u"The process has already tried to start.");
@@ -31,7 +32,7 @@ void PlatformSubProcess::Start() {
this->state_->status = SubProcessStatus::Running;
auto thread = std::thread([state = state_] {
- std::lock_guard lock_guard(state->lock);
+ std::unique_lock lock(state->mutex);
state->exit_result = state->impl->PlatformWaitForProcess();
state->status = SubProcessStatus::Exited;
state->condition_variable.notify_all();
@@ -47,7 +48,7 @@ void PlatformSubProcess::Start() {
void PlatformSubProcess::Wait(
std::optional<std::chrono::milliseconds> wait_time) {
- std::lock_guard lock_guard(this->state_->lock);
+ std::lock_guard lock_guard(this->lock_);
if (this->state_->status == SubProcessStatus::Prepare) {
throw SubProcessException(
@@ -68,15 +69,15 @@ void PlatformSubProcess::Wait(
};
if (wait_time) {
- this->state_->condition_variable.wait_for(this->state_->lock, *wait_time,
+ this->state_->condition_variable.wait_for(this->lock_, *wait_time,
predicate);
} else {
- this->state_->condition_variable.wait(this->state_->lock, predicate);
+ this->state_->condition_variable.wait(this->lock_, predicate);
}
}
void PlatformSubProcess::Kill() {
- std::lock_guard lock_guard(this->state_->lock);
+ std::lock_guard lock_guard(this->lock_);
if (this->state_->status == SubProcessStatus::Prepare) {
throw SubProcessException(u"The process does not start. Can't kill it.");
@@ -99,12 +100,12 @@ void PlatformSubProcess::Kill() {
}
SubProcessStatus PlatformSubProcess::GetStatus() {
- std::lock_guard lock_guard(this->state_->lock);
+ std::lock_guard lock_guard(this->lock_);
return this->state_->status;
}
SubProcessExitResult PlatformSubProcess::GetExitResult() {
- std::lock_guard lock_guard(this->state_->lock);
+ std::lock_guard lock_guard(this->lock_);
if (this->state_->status == SubProcessStatus::Prepare) {
throw SubProcessException(
@@ -145,6 +146,15 @@ SubProcess SubProcess::Create(String program, std::vector<String> arguments,
return SubProcess(std::move(start_info));
}
+SubProcessExitResult SubProcess::Call(
+ String program, std::vector<String> arguments,
+ std::unordered_map<String, String> environments) {
+ auto process =
+ Create(std::move(program), std::move(arguments), std::move(environments));
+ process.Wait();
+ return process.GetExitResult();
+}
+
SubProcess::SubProcess(SubProcessStartInfo start_info) {
platform_process_.reset(new PlatformSubProcess(
std::move(start_info), std::make_shared<ThisPlatformSubProcessImpl>()));
diff --git a/test/common/SubProcessTest.cpp b/test/common/SubProcessTest.cpp
index f2df2142..e42ee943 100644
--- a/test/common/SubProcessTest.cpp
+++ b/test/common/SubProcessTest.cpp
@@ -7,6 +7,8 @@ using cru::SubProcess;
TEST_CASE("SubProcess", "[subprocess]") {
SECTION("should work.") {
SubProcess process = SubProcess::Create(u"echo", {u"abc"});
+ process.Wait();
+ REQUIRE(process.GetExitResult().IsSuccess());
auto output = process.GetStdoutStream()->ReadToEndAsUtf8String();
REQUIRE(output == u"abc\n");
}