summaryrefslogtreecommitdiff
path: root/runtime/exec_utils.cc
diff options
context:
space:
mode:
author Jiakai Zhang <jiakaiz@google.com> 2022-09-13 14:14:16 +0100
committer Treehugger Robot <treehugger-gerrit@google.com> 2022-09-16 20:14:46 +0000
commit1a8cc460546a3bf5f55acf46efb5073d5ed412d3 (patch)
tree24c2ffff1efae12e9f6f10c5a8df74b8ff7a2e0e /runtime/exec_utils.cc
parent4c9498e8f1c8ef8c54cfd7462e24a505690cdc10 (diff)
odrefresh: Report dex2oat result for each stage.
This is the first step to improve odrefresh metrics collection. More CLs will follow. After the change, the metrics should tell: - whether dex2oat is invoked or not - whether dex2oat crashed or exited with a code Partially cherry-picked from commit fa152ba922a6301a10671d4684b75fe8cb2a2330 Bug: 246534524 Test: m test-art-host-gtest-art_runtime_tests Test: atest ArtGtestsTargetChroot:OdRefreshTest Merged-In: Id962a6e6a765371d290a836c51059d725c9250f3 Change-Id: I69ddf64552d4f2e51e111a40871890d41c88721d
Diffstat (limited to 'runtime/exec_utils.cc')
-rw-r--r--runtime/exec_utils.cc99
1 files changed, 45 insertions, 54 deletions
diff --git a/runtime/exec_utils.cc b/runtime/exec_utils.cc
index 929f09f784..dd389f8c97 100644
--- a/runtime/exec_utils.cc
+++ b/runtime/exec_utils.cc
@@ -102,10 +102,10 @@ pid_t ExecWithoutWait(const std::vector<std::string>& arg_vector, std::string* e
}
}
-int WaitChild(pid_t pid,
- const std::vector<std::string>& arg_vector,
- bool no_wait,
- std::string* error_msg) {
+ExecResult WaitChild(pid_t pid,
+ const std::vector<std::string>& arg_vector,
+ bool no_wait,
+ std::string* error_msg) {
siginfo_t info;
// WNOWAIT leaves the child in a waitable state. The call is still blocking.
int options = WEXITED | (no_wait ? WNOWAIT : 0);
@@ -114,7 +114,7 @@ int WaitChild(pid_t pid,
ToCommandLine(arg_vector).c_str(),
pid,
strerror(errno));
- return -1;
+ return {.status = ExecResult::kUnknown};
}
if (info.si_pid != pid) {
*error_msg = StringPrintf("waitid failed for (%s): wanted pid %d, got %d: %s",
@@ -122,38 +122,38 @@ int WaitChild(pid_t pid,
pid,
info.si_pid,
strerror(errno));
- return -1;
+ return {.status = ExecResult::kUnknown};
}
if (info.si_code != CLD_EXITED) {
*error_msg =
StringPrintf("Failed to execute (%s) because the child process is terminated by signal %d",
ToCommandLine(arg_vector).c_str(),
info.si_status);
- return -1;
+ return {.status = ExecResult::kSignaled, .signal = info.si_status};
}
- return info.si_status;
+ return {.status = ExecResult::kExited, .exit_code = info.si_status};
}
// A fallback implementation of `WaitChildWithTimeout` that creates a thread to wait instead of
// relying on `pidfd_open`.
-int WaitChildWithTimeoutFallback(pid_t pid,
- const std::vector<std::string>& arg_vector,
- int timeout_ms,
- bool* timed_out,
- std::string* error_msg) {
+ExecResult WaitChildWithTimeoutFallback(pid_t pid,
+ const std::vector<std::string>& arg_vector,
+ int timeout_ms,
+ std::string* error_msg) {
bool child_exited = false;
+ bool timed_out = false;
std::condition_variable cv;
std::mutex m;
std::thread wait_thread([&]() {
std::unique_lock<std::mutex> lock(m);
if (!cv.wait_for(lock, std::chrono::milliseconds(timeout_ms), [&] { return child_exited; })) {
- *timed_out = true;
+ timed_out = true;
kill(pid, SIGKILL);
}
});
- int status = WaitChild(pid, arg_vector, /*no_wait=*/true, error_msg);
+ ExecResult result = WaitChild(pid, arg_vector, /*no_wait=*/true, error_msg);
{
std::unique_lock<std::mutex> lock(m);
@@ -163,24 +163,23 @@ int WaitChildWithTimeoutFallback(pid_t pid,
wait_thread.join();
// The timeout error should have a higher priority than any other error.
- if (*timed_out) {
+ if (timed_out) {
*error_msg =
StringPrintf("Failed to execute (%s) because the child process timed out after %dms",
ToCommandLine(arg_vector).c_str(),
timeout_ms);
- return -1;
+ return ExecResult{.status = ExecResult::kTimedOut};
}
- return status;
+ return result;
}
// Waits for the child process to finish and leaves the child in a waitable state.
-int WaitChildWithTimeout(pid_t pid,
- unique_fd pidfd,
- const std::vector<std::string>& arg_vector,
- int timeout_ms,
- bool* timed_out,
- std::string* error_msg) {
+ExecResult WaitChildWithTimeout(pid_t pid,
+ unique_fd pidfd,
+ const std::vector<std::string>& arg_vector,
+ int timeout_ms,
+ std::string* error_msg) {
auto cleanup = android::base::make_scope_guard([&]() {
kill(pid, SIGKILL);
std::string ignored_error_msg;
@@ -196,15 +195,14 @@ int WaitChildWithTimeout(pid_t pid,
if (poll_ret < 0) {
*error_msg = StringPrintf("poll failed for pid %d: %s", pid, strerror(errno));
- return -1;
+ return {.status = ExecResult::kUnknown};
}
if (poll_ret == 0) {
- *timed_out = true;
*error_msg =
StringPrintf("Failed to execute (%s) because the child process timed out after %dms",
ToCommandLine(arg_vector).c_str(),
timeout_ms);
- return -1;
+ return {.status = ExecResult::kTimedOut};
}
cleanup.Disable();
@@ -242,54 +240,47 @@ bool ParseProcStat(const std::string& stat_content,
int ExecUtils::ExecAndReturnCode(const std::vector<std::string>& arg_vector,
std::string* error_msg) const {
- bool ignored_timed_out;
- return ExecAndReturnCode(arg_vector, /*timeout_sec=*/-1, &ignored_timed_out, error_msg);
+ return ExecAndReturnResult(arg_vector, /*timeout_sec=*/-1, error_msg).exit_code;
}
-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, ExecCallbacks(), timed_out, /*stat=*/nullptr, error_msg);
+ExecResult ExecUtils::ExecAndReturnResult(const std::vector<std::string>& arg_vector,
+ int timeout_sec,
+ std::string* error_msg) const {
+ return ExecAndReturnResult(arg_vector, timeout_sec, ExecCallbacks(), /*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 {
- *timed_out = false;
-
+ExecResult ExecUtils::ExecAndReturnResult(const std::vector<std::string>& arg_vector,
+ int timeout_sec,
+ const ExecCallbacks& callbacks,
+ /*out*/ ProcessStat* stat,
+ /*out*/ std::string* error_msg) const {
if (timeout_sec > INT_MAX / 1000) {
*error_msg = "Timeout too large";
- return -1;
+ return {.status = ExecResult::kStartFailed};
}
// Start subprocess.
pid_t pid = ExecWithoutWait(arg_vector, error_msg);
if (pid == -1) {
- return -1;
+ return {.status = ExecResult::kStartFailed};
}
callbacks.on_start(pid);
// Wait for subprocess to finish.
- int status;
+ ExecResult result;
if (timeout_sec >= 0) {
unique_fd pidfd = PidfdOpen(pid);
if (pidfd.get() >= 0) {
- status = WaitChildWithTimeout(
- pid, std::move(pidfd), arg_vector, timeout_sec * 1000, timed_out, error_msg);
+ result =
+ WaitChildWithTimeout(pid, std::move(pidfd), arg_vector, timeout_sec * 1000, error_msg);
} else {
LOG(DEBUG) << StringPrintf(
"pidfd_open failed for pid %d: %s, falling back", pid, strerror(errno));
- status =
- WaitChildWithTimeoutFallback(pid, arg_vector, timeout_sec * 1000, timed_out, error_msg);
+ result = WaitChildWithTimeoutFallback(pid, arg_vector, timeout_sec * 1000, error_msg);
}
} else {
- status = WaitChild(pid, arg_vector, /*no_wait=*/true, error_msg);
+ result = WaitChild(pid, arg_vector, /*no_wait=*/true, error_msg);
}
if (stat != nullptr) {
@@ -303,12 +294,12 @@ int ExecUtils::ExecAndReturnCode(const std::vector<std::string>& arg_vector,
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 &&
- local_error_msg.find("waitid failed") == 0) {
+ if (WaitChild(pid, arg_vector, /*no_wait=*/false, &local_error_msg).status ==
+ ExecResult::kUnknown) {
LOG(ERROR) << "Failed to clean up child process '" << arg_vector[0] << "': " << local_error_msg;
}
- return status;
+ return result;
}
bool ExecUtils::Exec(const std::vector<std::string>& arg_vector, std::string* error_msg) const {