1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 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 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 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. 15 */ 16 17 #include "workload.h" 18 19 #include <errno.h> 20 #include <fcntl.h> 21 #include <sys/prctl.h> 22 #include <sys/wait.h> 23 #include <unistd.h> 24 25 #include <android-base/logging.h> 26 27 std::unique_ptr<Workload> Workload::CreateWorkload(const std::vector<std::string>& args) { 28 std::unique_ptr<Workload> workload(new Workload(args, std::function<void ()>())); 29 if (workload != nullptr && workload->CreateNewProcess()) { 30 return workload; 31 } 32 return nullptr; 33 } 34 35 std::unique_ptr<Workload> Workload::CreateWorkload(const std::function<void ()>& function) { 36 std::unique_ptr<Workload> workload(new Workload(std::vector<std::string>(), function)); 37 if (workload != nullptr && workload->CreateNewProcess()) { 38 return workload; 39 } 40 return nullptr; 41 } 42 43 Workload::~Workload() { 44 if (work_pid_ != -1 && work_state_ != NotYetCreateNewProcess) { 45 if (!Workload::WaitChildProcess(false, false)) { 46 kill(work_pid_, SIGKILL); 47 Workload::WaitChildProcess(true, true); 48 } 49 } 50 if (start_signal_fd_ != -1) { 51 close(start_signal_fd_); 52 } 53 if (exec_child_fd_ != -1) { 54 close(exec_child_fd_); 55 } 56 } 57 58 bool Workload::CreateNewProcess() { 59 CHECK_EQ(work_state_, NotYetCreateNewProcess); 60 61 int start_signal_pipe[2]; 62 if (pipe2(start_signal_pipe, O_CLOEXEC) != 0) { 63 PLOG(ERROR) << "pipe2() failed"; 64 return false; 65 } 66 67 int exec_child_pipe[2]; 68 if (pipe2(exec_child_pipe, O_CLOEXEC) != 0) { 69 PLOG(ERROR) << "pipe2() failed"; 70 close(start_signal_pipe[0]); 71 close(start_signal_pipe[1]); 72 return false; 73 } 74 75 pid_t pid = fork(); 76 if (pid == -1) { 77 PLOG(ERROR) << "fork() failed"; 78 close(start_signal_pipe[0]); 79 close(start_signal_pipe[1]); 80 close(exec_child_pipe[0]); 81 close(exec_child_pipe[1]); 82 return false; 83 } else if (pid == 0) { 84 // In child process. 85 close(start_signal_pipe[1]); 86 close(exec_child_pipe[0]); 87 ChildProcessFn(start_signal_pipe[0], exec_child_pipe[1]); 88 _exit(0); 89 } 90 // In parent process. 91 close(start_signal_pipe[0]); 92 close(exec_child_pipe[1]); 93 start_signal_fd_ = start_signal_pipe[1]; 94 exec_child_fd_ = exec_child_pipe[0]; 95 work_pid_ = pid; 96 work_state_ = NotYetStartNewProcess; 97 return true; 98 } 99 100 void Workload::ChildProcessFn(int start_signal_fd, int exec_child_fd) { 101 // Die if parent exits. 102 prctl(PR_SET_PDEATHSIG, SIGHUP, 0, 0, 0); 103 104 char start_signal = 0; 105 ssize_t nread = TEMP_FAILURE_RETRY(read(start_signal_fd, &start_signal, 1)); 106 if (nread == 1 && start_signal == 1) { 107 close(start_signal_fd); 108 if (child_proc_function_) { 109 close(exec_child_fd); 110 child_proc_function_(); 111 } else { 112 char* argv[child_proc_args_.size() + 1]; 113 for (size_t i = 0; i < child_proc_args_.size(); ++i) { 114 argv[i] = &child_proc_args_[i][0]; 115 } 116 argv[child_proc_args_.size()] = nullptr; 117 execvp(argv[0], argv); 118 // If execvp() succeed, we will not arrive here. But if it failed, we need to 119 // report the failure to the parent process by writing 1 to exec_child_fd. 120 int saved_errno = errno; 121 char exec_child_failed = 1; 122 TEMP_FAILURE_RETRY(write(exec_child_fd, &exec_child_failed, 1)); 123 close(exec_child_fd); 124 errno = saved_errno; 125 PLOG(ERROR) << "child process failed to execvp(" << argv[0] << ")"; 126 } 127 } else { 128 PLOG(ERROR) << "child process failed to receive start_signal, nread = " << nread; 129 } 130 } 131 132 bool Workload::Start() { 133 CHECK_EQ(work_state_, NotYetStartNewProcess); 134 char start_signal = 1; 135 ssize_t nwrite = TEMP_FAILURE_RETRY(write(start_signal_fd_, &start_signal, 1)); 136 if (nwrite != 1) { 137 PLOG(ERROR) << "write start signal failed"; 138 return false; 139 } 140 char exec_child_failed; 141 ssize_t nread = TEMP_FAILURE_RETRY(read(exec_child_fd_, &exec_child_failed, 1)); 142 if (nread != 0) { 143 if (nread == -1) { 144 PLOG(ERROR) << "failed to receive error message from child process"; 145 } else { 146 LOG(ERROR) << "received error message from child process"; 147 } 148 return false; 149 } 150 work_state_ = Started; 151 return true; 152 } 153 154 bool Workload::WaitChildProcess(bool wait_forever, bool is_child_killed) { 155 bool finished = false; 156 int status; 157 pid_t result = TEMP_FAILURE_RETRY(waitpid(work_pid_, &status, (wait_forever ? 0 : WNOHANG))); 158 if (result == work_pid_) { 159 finished = true; 160 if (WIFSIGNALED(status)) { 161 if (!(is_child_killed && WTERMSIG(status) == SIGKILL)) { 162 LOG(WARNING) << "child process was terminated by signal " << strsignal(WTERMSIG(status)); 163 } 164 } else if (WIFEXITED(status) && WEXITSTATUS(status) != 0) { 165 LOG(WARNING) << "child process exited with exit code " << WEXITSTATUS(status); 166 } 167 } else if (result == -1) { 168 PLOG(ERROR) << "waitpid() failed"; 169 } 170 return finished; 171 } 172