diff options
author | 2022-09-09 11:58:56 +0100 | |
---|---|---|
committer | 2022-09-16 20:14:46 +0000 | |
commit | 4c9498e8f1c8ef8c54cfd7462e24a505690cdc10 (patch) | |
tree | 64248e7108103d2e00928f3968b2dc4e98a81082 | |
parent | 5494695148b63ab33e6e5e178dcef5fa6380116c (diff) |
Change ExecUtils to support callbacks.
artd needs the callbacks to get the pid in order to kill the subprocess.
Partially cherry-picked from
commit 659f49bdb1263ceb26f666052f3ef7e4732b4eb2
Bug: 244412198
Test: m test-art-host-gtest-art_runtime_tests
Merged-In: I8c40949b5ed88ff85ddedad9d86f0b9bbfddb98d
Change-Id: Ia28410bdf6314178756ee5e3a94000dc6f3ecc97
-rw-r--r-- | runtime/exec_utils.cc | 8 | ||||
-rw-r--r-- | runtime/exec_utils.h | 14 | ||||
-rw-r--r-- | runtime/exec_utils_test.cc | 40 |
3 files changed, 56 insertions, 6 deletions
diff --git a/runtime/exec_utils.cc b/runtime/exec_utils.cc index cc4667c3a6..929f09f784 100644 --- a/runtime/exec_utils.cc +++ b/runtime/exec_utils.cc @@ -250,11 +250,13 @@ int ExecUtils::ExecAndReturnCode(const std::vector<std::string>& arg_vector, int timeout_sec, bool* timed_out, std::string* error_msg) const { - return ExecAndReturnCode(arg_vector, timeout_sec, timed_out, /*stat=*/nullptr, error_msg); + return ExecAndReturnCode( + arg_vector, timeout_sec, ExecCallbacks(), timed_out, /*stat=*/nullptr, error_msg); } int ExecUtils::ExecAndReturnCode(const std::vector<std::string>& arg_vector, int timeout_sec, + const ExecCallbacks& callbacks, /*out*/ bool* timed_out, /*out*/ ProcessStat* stat, /*out*/ std::string* error_msg) const { @@ -271,6 +273,8 @@ int ExecUtils::ExecAndReturnCode(const std::vector<std::string>& arg_vector, return -1; } + callbacks.on_start(pid); + // Wait for subprocess to finish. int status; if (timeout_sec >= 0) { @@ -295,6 +299,8 @@ int ExecUtils::ExecAndReturnCode(const std::vector<std::string>& arg_vector, } } + callbacks.on_end(pid); + std::string local_error_msg; // TODO(jiakaiz): Use better logic to detect waitid failure. if (WaitChild(pid, arg_vector, /*no_wait=*/false, &local_error_msg) < 0 && diff --git a/runtime/exec_utils.h b/runtime/exec_utils.h index 751c64d9c8..aa0d0fc932 100644 --- a/runtime/exec_utils.h +++ b/runtime/exec_utils.h @@ -19,6 +19,7 @@ #include <time.h> +#include <functional> #include <string> #include <vector> @@ -34,6 +35,14 @@ struct ProcessStat { int cpu_time_ms = 0; }; +struct ExecCallbacks { + // Called in the parent process as soon as the child process is forked. + std::function<void(pid_t pid)> on_start = [](pid_t) {}; + // Called in the parent process after the child process exits while still in a waitable state, no + // matter the child process succeeds or not. + std::function<void(pid_t pid)> on_end = [](pid_t) {}; +}; + // Wrapper on fork/execv to run a command in a subprocess. // These spawn child processes using the environment as it was set when the single instance // of the runtime (Runtime::Current()) was started. If no instance of the runtime was started, it @@ -57,10 +66,11 @@ class ExecUtils { /*out*/ bool* timed_out, /*out*/ std::string* error_msg) const; - // Same as above, but also collects stat of the process. The stat is collected no matter the child - // process succeeds or not. + // Same as above, but also collects stat of the process and calls callbacks. The stat is collected + // no matter the child process succeeds or not. virtual int ExecAndReturnCode(const std::vector<std::string>& arg_vector, int timeout_sec, + const ExecCallbacks& callbacks, /*out*/ bool* timed_out, /*out*/ ProcessStat* stat, /*out*/ std::string* error_msg) const; diff --git a/runtime/exec_utils_test.cc b/runtime/exec_utils_test.cc index c09bf407f4..e9bbd8fd2b 100644 --- a/runtime/exec_utils_test.cc +++ b/runtime/exec_utils_test.cc @@ -34,7 +34,12 @@ namespace art { using ::testing::_; +using ::testing::AllOf; +using ::testing::Gt; using ::testing::HasSubstr; +using ::testing::InSequence; +using ::testing::MockFunction; +using ::testing::Ne; using ::testing::Return; std::string PrettyArguments(const char* signature); @@ -201,8 +206,9 @@ TEST_P(ExecUtilsTest, ExecStat) { EXPECT_CALL(*exec_utils_, GetUptimeMs()).WillOnce(Return(1620344887ll)); EXPECT_CALL(*exec_utils_, GetTicksPerSec()).WillOnce(Return(100)); - ASSERT_EQ( - exec_utils_->ExecAndReturnCode(command, /*timeout_sec=*/-1, &timed_out, &stat, &error_msg), 0) + ASSERT_EQ(exec_utils_->ExecAndReturnCode( + command, /*timeout_sec=*/-1, ExecCallbacks(), &timed_out, &stat, &error_msg), + 0) << error_msg; EXPECT_EQ(stat.cpu_time_ms, 990); @@ -224,12 +230,40 @@ TEST_P(ExecUtilsTest, ExecStatFailed) { EXPECT_CALL(*exec_utils_, GetTicksPerSec()).WillOnce(Return(100)); // This will always time out. - exec_utils_->ExecAndReturnCode(command, /*timeout_sec=*/1, &timed_out, &stat, &error_msg); + exec_utils_->ExecAndReturnCode( + command, /*timeout_sec=*/1, ExecCallbacks(), &timed_out, &stat, &error_msg); EXPECT_EQ(stat.cpu_time_ms, 990); EXPECT_EQ(stat.wall_time_ms, 1007); } +TEST_P(ExecUtilsTest, ExecCallbacks) { + MockFunction<void(pid_t)> on_start; + MockFunction<void(pid_t)> on_end; + + { + InSequence s; + EXPECT_CALL(on_start, Call(AllOf(Gt(0), Ne(getpid())))); + EXPECT_CALL(on_end, Call(AllOf(Gt(0), Ne(getpid())))); + } + + std::vector<std::string> command; + command.push_back(GetBin("id")); + + std::string error_msg; + bool timed_out; + + exec_utils_->ExecAndReturnCode(command, + /*timeout_sec=*/-1, + ExecCallbacks{ + .on_start = on_start.AsStdFunction(), + .on_end = on_end.AsStdFunction(), + }, + &timed_out, + /*stat=*/nullptr, + &error_msg); +} + INSTANTIATE_TEST_SUITE_P(AlwaysOrNeverFallback, ExecUtilsTest, testing::Values(true, false)); } // namespace art |