2 * Copyright (C) 2015 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
24 #include <base/logging.h>
26 std::unique_ptr<Workload> Workload::CreateWorkload(const std::vector<std::string>& args) {
27 std::unique_ptr<Workload> workload(new Workload(args));
28 if (workload != nullptr && workload->CreateNewProcess()) {
34 Workload::~Workload() {
35 if (work_pid_ != -1 && work_state_ != NotYetCreateNewProcess) {
36 if (!Workload::WaitChildProcess(false)) {
37 kill(work_pid_, SIGKILL);
38 Workload::WaitChildProcess(true);
41 if (start_signal_fd_ != -1) {
42 close(start_signal_fd_);
44 if (exec_child_fd_ != -1) {
45 close(exec_child_fd_);
49 static void ChildProcessFn(std::vector<std::string>& args, int start_signal_fd, int exec_child_fd);
51 bool Workload::CreateNewProcess() {
52 CHECK_EQ(work_state_, NotYetCreateNewProcess);
54 int start_signal_pipe[2];
55 if (pipe2(start_signal_pipe, O_CLOEXEC) != 0) {
56 PLOG(ERROR) << "pipe2() failed";
60 int exec_child_pipe[2];
61 if (pipe2(exec_child_pipe, O_CLOEXEC) != 0) {
62 PLOG(ERROR) << "pipe2() failed";
63 close(start_signal_pipe[0]);
64 close(start_signal_pipe[1]);
70 PLOG(ERROR) << "fork() failed";
71 close(start_signal_pipe[0]);
72 close(start_signal_pipe[1]);
73 close(exec_child_pipe[0]);
74 close(exec_child_pipe[1]);
76 } else if (pid == 0) {
78 close(start_signal_pipe[1]);
79 close(exec_child_pipe[0]);
80 ChildProcessFn(args_, start_signal_pipe[0], exec_child_pipe[1]);
83 close(start_signal_pipe[0]);
84 close(exec_child_pipe[1]);
85 start_signal_fd_ = start_signal_pipe[1];
86 exec_child_fd_ = exec_child_pipe[0];
88 work_state_ = NotYetStartNewProcess;
92 static void ChildProcessFn(std::vector<std::string>& args, int start_signal_fd, int exec_child_fd) {
93 std::vector<char*> argv(args.size() + 1);
94 for (size_t i = 0; i < args.size(); ++i) {
95 argv[i] = &args[i][0];
97 argv[args.size()] = nullptr;
99 char start_signal = 0;
100 ssize_t nread = TEMP_FAILURE_RETRY(read(start_signal_fd, &start_signal, 1));
101 if (nread == 1 && start_signal == 1) {
102 close(start_signal_fd);
103 execvp(argv[0], argv.data());
104 // If execvp() succeed, we will not arrive here. But if it failed, we need to
105 // report the failure to the parent process by writing 1 to exec_child_fd.
106 int saved_errno = errno;
107 char exec_child_failed = 1;
108 TEMP_FAILURE_RETRY(write(exec_child_fd, &exec_child_failed, 1));
109 close(exec_child_fd);
111 PLOG(ERROR) << "child process failed to execvp(" << argv[0] << ")";
113 PLOG(ERROR) << "child process failed to receive start_signal, nread = " << nread;
117 bool Workload::Start() {
118 CHECK_EQ(work_state_, NotYetStartNewProcess);
119 char start_signal = 1;
120 ssize_t nwrite = TEMP_FAILURE_RETRY(write(start_signal_fd_, &start_signal, 1));
122 PLOG(ERROR) << "write start signal failed";
125 char exec_child_failed;
126 ssize_t nread = TEMP_FAILURE_RETRY(read(exec_child_fd_, &exec_child_failed, 1));
129 PLOG(ERROR) << "failed to receive error message from child process";
131 LOG(ERROR) << "received error message from child process";
135 work_state_ = Started;
139 bool Workload::WaitChildProcess(bool wait_forever) {
140 bool finished = false;
142 pid_t result = TEMP_FAILURE_RETRY(waitpid(work_pid_, &status, (wait_forever ? 0 : WNOHANG)));
143 if (result == work_pid_) {
145 if (WIFSIGNALED(status)) {
146 LOG(WARNING) << "child process was terminated by signal " << strsignal(WTERMSIG(status));
147 } else if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
148 LOG(WARNING) << "child process exited with exit code " << WEXITSTATUS(status);
150 } else if (result == -1) {
151 PLOG(ERROR) << "waitpid() failed";