blob: 7c2ec0152303c2535f88205e0f87e73303f956e6 [file] [log] [blame]
Primiano Tucci6d7d2542020-03-17 20:03:48 +00001/*
2 * Copyright (C) 2020 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 "perfetto/ext/base/subprocess.h"
18
Primiano Tucci1797cd12020-04-14 09:43:24 +010019#if PERFETTO_HAS_SUBPROCESS()
20
Primiano Tucci6d7d2542020-03-17 20:03:48 +000021#include <poll.h>
22#include <signal.h>
23#include <stdio.h>
Primiano Tucciff68cac2020-08-06 18:13:17 +020024#include <sys/resource.h>
Primiano Tucci6d7d2542020-03-17 20:03:48 +000025#include <sys/types.h>
26#include <sys/wait.h>
27#include <unistd.h>
28
29#include <algorithm>
30#include <thread>
Primiano Tuccie1a28482020-08-06 14:43:54 +020031#include <tuple>
Primiano Tucci6d7d2542020-03-17 20:03:48 +000032
33#include "perfetto/base/build_config.h"
34#include "perfetto/base/logging.h"
35#include "perfetto/base/time.h"
36#include "perfetto/ext/base/utils.h"
37
38#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
39 PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
40#include <sys/prctl.h>
41#endif
42
43// In MacOS this is not defined in any header.
44extern "C" char** environ;
45
46namespace perfetto {
47namespace base {
48
49namespace {
50
51struct ChildProcessArgs {
52 Subprocess::Args* create_args;
53 const char* exec_cmd = nullptr;
54 std::vector<char*> argv;
55 std::vector<char*> env;
56 int stdin_pipe_rd = -1;
57 int stdouterr_pipe_wr = -1;
58};
59
60// Don't add any dynamic allocation in this function. This will be invoked
61// under a fork(), potentially in a state where the allocator lock is held.
62void __attribute__((noreturn)) ChildProcess(ChildProcessArgs* args) {
63#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
64 PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
65 // In no case we want a child process to outlive its parent process. This is
66 // relevant for tests, so that a test failure/crash doesn't leave child
67 // processes around that get reparented to init.
68 prctl(PR_SET_PDEATHSIG, SIGKILL);
69#endif
70
71 auto die = [args](const char* err) __attribute__((noreturn)) {
72 base::ignore_result(write(args->stdouterr_pipe_wr, err, strlen(err)));
73 base::ignore_result(write(args->stdouterr_pipe_wr, "\n", 1));
74 // From https://www.gnu.org/software/libc/manual/html_node/Exit-Status.html
75 // "In particular, the value 128 is used to indicate failure to execute
76 // another program in a subprocess. This convention is not universally
77 // obeyed, but it is a good idea to follow it in your programs."
78 _exit(128);
79 };
80
81 auto set_fd_close_on_exec = [&die](int fd, bool close_on_exec) {
82 int flags = fcntl(fd, F_GETFD, 0);
83 if (flags < 0)
84 die("fcntl(F_GETFD) failed");
85 flags = close_on_exec ? (flags | FD_CLOEXEC) : (flags & ~FD_CLOEXEC);
86 if (fcntl(fd, F_SETFD, flags) < 0)
87 die("fcntl(F_SETFD) failed");
88 };
89
90 if (getppid() == 1)
91 die("terminating because parent process died");
92
93 if (dup2(args->stdin_pipe_rd, STDIN_FILENO) == -1)
94 die("Failed to dup2(STDIN)");
95 close(args->stdin_pipe_rd);
96
97 switch (args->create_args->stdout_mode) {
98 case Subprocess::kInherit:
99 break;
100 case Subprocess::kDevNull: {
101 if (dup2(open("/dev/null", O_RDWR), STDOUT_FILENO) == -1)
102 die("Failed to dup2(STDOUT)");
103 break;
104 }
105 case Subprocess::kBuffer:
106 if (dup2(args->stdouterr_pipe_wr, STDOUT_FILENO) == -1)
107 die("Failed to dup2(STDOUT)");
108 break;
Primiano Tucciff68cac2020-08-06 18:13:17 +0200109 case Subprocess::kFd:
110 if (dup2(*args->create_args->out_fd, STDOUT_FILENO) == -1)
111 die("Failed to dup2(STDOUT)");
112 break;
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000113 }
114
115 switch (args->create_args->stderr_mode) {
116 case Subprocess::kInherit:
117 break;
118 case Subprocess::kDevNull: {
119 if (dup2(open("/dev/null", O_RDWR), STDERR_FILENO) == -1)
120 die("Failed to dup2(STDERR)");
121 break;
122 }
123 case Subprocess::kBuffer:
124 if (dup2(args->stdouterr_pipe_wr, STDERR_FILENO) == -1)
125 die("Failed to dup2(STDERR)");
126 break;
Primiano Tucciff68cac2020-08-06 18:13:17 +0200127 case Subprocess::kFd:
128 if (dup2(*args->create_args->out_fd, STDERR_FILENO) == -1)
129 die("Failed to dup2(STDERR)");
130 break;
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000131 }
132
133 // Close all FDs % stdin/out/err and the ones that the client explicitly
134 // asked to retain. The reason for this is twofold:
135 // 1. For exec-only (i.e. entrypoint == empty) cases: it avoids leaking FDs
136 // that didn't get marked as O_CLOEXEC by accident.
137 // 2. In fork() mode (entrypoint not empty) avoids retaining a dup of eventfds
138 // that would prevent the parent process to receive EOFs (tests usually use
139 // pipes as a synchronization mechanism between subprocesses).
140 const auto& preserve_fds = args->create_args->preserve_fds;
141 for (int i = 0; i < 512; i++) {
142 if (i != STDIN_FILENO && i != STDERR_FILENO && i != STDOUT_FILENO &&
143 i != args->stdouterr_pipe_wr &&
144 !std::count(preserve_fds.begin(), preserve_fds.end(), i)) {
145 close(i);
146 }
147 }
148
149 // Clears O_CLOEXEC from stdin/out/err. These are the only FDs that we want
150 // to be preserved after the exec().
151 set_fd_close_on_exec(STDIN_FILENO, false);
152 set_fd_close_on_exec(STDOUT_FILENO, false);
153 set_fd_close_on_exec(STDERR_FILENO, false);
154
155 // If the caller specified a std::function entrypoint, run that first.
156 if (args->create_args->entrypoint_for_testing)
157 args->create_args->entrypoint_for_testing();
158
159 // If the caller specified only an entrypoint, without any args, exit now.
160 // Otherwise proceed with the exec() below.
161 if (!args->exec_cmd)
162 _exit(0);
163
164 // If |args[0]| is a path use execv() (which takes a path), othewise use
165 // exevp(), which uses the shell and follows PATH.
166 if (strchr(args->exec_cmd, '/')) {
167 char** env = args->env.empty() ? environ : args->env.data();
168 execve(args->exec_cmd, args->argv.data(), env);
169 } else {
170 // There is no execvpe() on Mac.
171 if (!args->env.empty())
172 die("A full path is required for |exec_cmd| when setting |env|");
173 execvp(args->exec_cmd, args->argv.data());
174 }
175
176 // Reached only if execv fails.
177 die("execve() failed");
178}
179
180} // namespace
181
Sami Kyostilaf059df72020-04-20 10:13:32 +0100182Subprocess::Args::Args(Args&&) noexcept = default;
183Subprocess::Args& Subprocess::Args::operator=(Args&&) = default;
184
Primiano Tucciff68cac2020-08-06 18:13:17 +0200185Subprocess::Subprocess(std::initializer_list<std::string> a) : args(a) {
186 s_.rusage.reset(new ResourceUsage());
187}
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000188
Primiano Tuccie1a28482020-08-06 14:43:54 +0200189Subprocess::Subprocess(Subprocess&& other) noexcept {
190 static_assert(sizeof(Subprocess) == sizeof(std::tuple<MovableState, Args>),
191 "base::Subprocess' move ctor needs updating");
192 s_ = std::move(other.s_);
193 args = std::move(other.args);
194
195 // Reset the state of the moved-from object.
196 other.s_.status = kNotStarted; // So the dtor doesn't try to kill().
197 other.~Subprocess();
198 new (&other) Subprocess();
199}
200
201Subprocess& Subprocess::operator=(Subprocess&& other) {
202 this->~Subprocess();
203 new (this) Subprocess(std::move(other));
204 return *this;
205}
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000206
207Subprocess::~Subprocess() {
Primiano Tuccie1a28482020-08-06 14:43:54 +0200208 if (s_.status == kRunning)
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000209 KillAndWaitForTermination();
Primiano Tuccie1a28482020-08-06 14:43:54 +0200210 PERFETTO_CHECK(!s_.waitpid_thread.joinable());
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000211}
212
213void Subprocess::Start() {
214 ChildProcessArgs proc_args;
215 proc_args.create_args = &args;
216
217 // Setup argv.
218 if (!args.exec_cmd.empty()) {
219 proc_args.exec_cmd = args.exec_cmd[0].c_str();
220 for (const std::string& arg : args.exec_cmd)
221 proc_args.argv.push_back(const_cast<char*>(arg.c_str()));
222 proc_args.argv.push_back(nullptr);
223
224 if (!args.argv0_override.empty())
225 proc_args.argv[0] = const_cast<char*>(args.argv0_override.c_str());
226 }
227
228 // Setup env.
229 if (!args.env.empty()) {
230 for (const std::string& str : args.env)
231 proc_args.env.push_back(const_cast<char*>(str.c_str()));
232 proc_args.env.push_back(nullptr);
233 }
234
235 // Setup the pipes for stdin/err redirection.
Primiano Tuccie1a28482020-08-06 14:43:54 +0200236 s_.stdin_pipe = base::Pipe::Create(base::Pipe::kWrNonBlock);
237 proc_args.stdin_pipe_rd = *s_.stdin_pipe.rd;
238 s_.stdouterr_pipe = base::Pipe::Create(base::Pipe::kRdNonBlock);
239 proc_args.stdouterr_pipe_wr = *s_.stdouterr_pipe.wr;
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000240
241 // Spawn the child process that will exec().
Primiano Tuccie1a28482020-08-06 14:43:54 +0200242 s_.pid = fork();
243 PERFETTO_CHECK(s_.pid >= 0);
244 if (s_.pid == 0) {
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000245 // Close the parent-ends of the pipes.
Primiano Tuccie1a28482020-08-06 14:43:54 +0200246 s_.stdin_pipe.wr.reset();
247 s_.stdouterr_pipe.rd.reset();
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000248 ChildProcess(&proc_args);
249 // ChildProcess() doesn't return, not even in case of failures.
250 PERFETTO_FATAL("not reached");
251 }
252
Primiano Tuccie1a28482020-08-06 14:43:54 +0200253 s_.status = kRunning;
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000254
255 // Close the child-end of the pipes.
Primiano Tuccie1a28482020-08-06 14:43:54 +0200256 // Deliberately NOT closing the s_.stdin_pipe.rd. This is to avoid crashing
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000257 // with a SIGPIPE if the process exits without consuming its stdin, while
258 // the parent tries to write() on the other end of the stdin pipe.
Primiano Tuccie1a28482020-08-06 14:43:54 +0200259 s_.stdouterr_pipe.wr.reset();
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000260
261 // Spawn a thread that is blocked on waitpid() and writes the termination
262 // status onto a pipe. The problem here is that waipid() doesn't have a
263 // timeout option and can't be passed to poll(). The alternative would be
264 // using a SIGCHLD handler, but anecdotally signal handlers introduce more
265 // problems than what they solve.
Primiano Tuccie1a28482020-08-06 14:43:54 +0200266 s_.exit_status_pipe = base::Pipe::Create(base::Pipe::kRdNonBlock);
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000267
268 // Both ends of the pipe are closed after the thread.join().
Primiano Tuccie1a28482020-08-06 14:43:54 +0200269 int pid = s_.pid;
270 int exit_status_pipe_wr = s_.exit_status_pipe.wr.release();
Primiano Tucciff68cac2020-08-06 18:13:17 +0200271 auto* rusage = s_.rusage.get();
272 s_.waitpid_thread = std::thread([pid, exit_status_pipe_wr, rusage] {
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000273 int pid_stat = -1;
Primiano Tucciff68cac2020-08-06 18:13:17 +0200274 struct rusage usg {};
275 int wait_res = PERFETTO_EINTR(wait4(pid, &pid_stat, 0, &usg));
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000276 PERFETTO_CHECK(wait_res == pid);
Primiano Tucciff68cac2020-08-06 18:13:17 +0200277
278 auto tv_to_ms = [](const struct timeval& tv) {
279 return static_cast<uint32_t>(tv.tv_sec * 1000 + tv.tv_usec / 1000);
280 };
281 rusage->cpu_utime_ms = tv_to_ms(usg.ru_utime);
282 rusage->cpu_stime_ms = tv_to_ms(usg.ru_stime);
283 rusage->max_rss_kb = static_cast<uint32_t>(usg.ru_maxrss) / 1000;
284 rusage->min_page_faults = static_cast<uint32_t>(usg.ru_minflt);
285 rusage->maj_page_faults = static_cast<uint32_t>(usg.ru_majflt);
286 rusage->vol_ctx_switch = static_cast<uint32_t>(usg.ru_nvcsw);
287 rusage->invol_ctx_switch = static_cast<uint32_t>(usg.ru_nivcsw);
288
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000289 base::ignore_result(PERFETTO_EINTR(
290 write(exit_status_pipe_wr, &pid_stat, sizeof(pid_stat))));
Ryan704bc822020-03-31 02:31:13 +0100291 PERFETTO_CHECK(close(exit_status_pipe_wr) == 0 || errno == EINTR);
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000292 });
293}
294
295Subprocess::Status Subprocess::Poll() {
Primiano Tuccie1a28482020-08-06 14:43:54 +0200296 if (s_.status != kRunning)
297 return s_.status; // Nothing to poll.
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000298 while (PollInternal(0 /* don't block*/)) {
299 }
Primiano Tuccie1a28482020-08-06 14:43:54 +0200300 return s_.status;
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000301}
302
303// |timeout_ms| semantic:
304// -1: Block indefinitely.
305// 0: Don't block, return immediately.
306// >0: Block for at most X ms.
307// Returns:
308// True: Read at least one fd (so there might be more queued).
309// False: if all fds reached quiescent (no data to read/write).
310bool Subprocess::PollInternal(int poll_timeout_ms) {
311 struct pollfd fds[3]{};
312 size_t num_fds = 0;
Primiano Tuccie1a28482020-08-06 14:43:54 +0200313 if (s_.exit_status_pipe.rd) {
314 fds[num_fds].fd = *s_.exit_status_pipe.rd;
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000315 fds[num_fds].events = POLLIN;
316 num_fds++;
317 }
Primiano Tuccie1a28482020-08-06 14:43:54 +0200318 if (s_.stdouterr_pipe.rd) {
319 fds[num_fds].fd = *s_.stdouterr_pipe.rd;
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000320 fds[num_fds].events = POLLIN;
321 num_fds++;
322 }
Primiano Tuccie1a28482020-08-06 14:43:54 +0200323 if (s_.stdin_pipe.wr) {
324 fds[num_fds].fd = *s_.stdin_pipe.wr;
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000325 fds[num_fds].events = POLLOUT;
326 num_fds++;
327 }
328
329 if (num_fds == 0)
330 return false;
331
332 auto nfds = static_cast<nfds_t>(num_fds);
333 int poll_res = PERFETTO_EINTR(poll(fds, nfds, poll_timeout_ms));
334 PERFETTO_CHECK(poll_res >= 0);
335
336 TryReadStdoutAndErr();
337 TryPushStdin();
338 TryReadExitStatus();
339
340 return poll_res > 0;
341}
342
343bool Subprocess::Wait(int timeout_ms) {
Primiano Tuccie1a28482020-08-06 14:43:54 +0200344 PERFETTO_CHECK(s_.status != kNotStarted);
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000345
346 // Break out of the loop only after both conditions are satisfied:
347 // - All stdout/stderr data has been read (if kBuffer).
348 // - The process exited.
349 // Note that the two events can happen arbitrary order. After the process
350 // exits, there might be still data in the pipe buffer, which we want to
351 // read fully.
352 //
353 // Instead, don't wait on the stdin to be fully written. The child process
354 // might exit prematurely (or crash). If that happens, we can end up in a
355 // state where the write(stdin_pipe_.wr) will never unblock.
356
357 const int64_t t_start = base::GetWallTimeMs().count();
Primiano Tuccie1a28482020-08-06 14:43:54 +0200358 while (s_.exit_status_pipe.rd || s_.stdouterr_pipe.rd) {
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000359 int poll_timeout_ms = -1; // Block until a FD is ready.
360 if (timeout_ms > 0) {
361 const int64_t now = GetWallTimeMs().count();
362 poll_timeout_ms = timeout_ms - static_cast<int>(now - t_start);
363 if (poll_timeout_ms <= 0)
364 return false;
365 }
366 PollInternal(poll_timeout_ms);
367 } // while(...)
368 return true;
369}
370
371bool Subprocess::Call(int timeout_ms) {
Primiano Tuccie1a28482020-08-06 14:43:54 +0200372 PERFETTO_CHECK(s_.status == kNotStarted);
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000373 Start();
374
375 if (!Wait(timeout_ms)) {
376 KillAndWaitForTermination();
377 // TryReadExitStatus must have joined the thread.
Primiano Tuccie1a28482020-08-06 14:43:54 +0200378 PERFETTO_DCHECK(!s_.waitpid_thread.joinable());
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000379 }
Primiano Tuccie1a28482020-08-06 14:43:54 +0200380 PERFETTO_DCHECK(s_.status != kRunning);
381 return s_.status == kExited && s_.returncode == 0;
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000382}
383
384void Subprocess::TryReadExitStatus() {
Primiano Tuccie1a28482020-08-06 14:43:54 +0200385 if (!s_.exit_status_pipe.rd)
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000386 return;
387
388 int pid_stat = -1;
Primiano Tuccie1a28482020-08-06 14:43:54 +0200389 int64_t rsize = PERFETTO_EINTR(
390 read(*s_.exit_status_pipe.rd, &pid_stat, sizeof(pid_stat)));
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000391 if (rsize < 0 && errno == EAGAIN)
392 return;
393
394 if (rsize > 0) {
395 PERFETTO_CHECK(rsize == sizeof(pid_stat));
396 } else if (rsize < 0) {
Primiano Tuccie1a28482020-08-06 14:43:54 +0200397 PERFETTO_PLOG("Subprocess read(s_.exit_status_pipe) failed");
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000398 }
Primiano Tuccie1a28482020-08-06 14:43:54 +0200399 s_.waitpid_thread.join();
400 s_.exit_status_pipe.rd.reset();
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000401
402 if (WIFEXITED(pid_stat)) {
Primiano Tuccie1a28482020-08-06 14:43:54 +0200403 s_.returncode = WEXITSTATUS(pid_stat);
404 s_.status = kExited;
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000405 } else if (WIFSIGNALED(pid_stat)) {
Primiano Tuccie1a28482020-08-06 14:43:54 +0200406 s_.returncode = 128 + WTERMSIG(pid_stat); // Follow bash convention.
407 s_.status = kKilledBySignal;
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000408 } else {
409 PERFETTO_FATAL("waitpid() returned an unexpected value (0x%x)", pid_stat);
410 }
411}
412
413// If the stidn pipe is still open, push input data and close it at the end.
414void Subprocess::TryPushStdin() {
Primiano Tuccie1a28482020-08-06 14:43:54 +0200415 if (!s_.stdin_pipe.wr)
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000416 return;
417
Primiano Tuccie1a28482020-08-06 14:43:54 +0200418 PERFETTO_DCHECK(args.input.empty() || s_.input_written < args.input.size());
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000419 if (args.input.size()) {
420 int64_t wsize =
Primiano Tuccie1a28482020-08-06 14:43:54 +0200421 PERFETTO_EINTR(write(*s_.stdin_pipe.wr, &args.input[s_.input_written],
422 args.input.size() - s_.input_written));
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000423 if (wsize < 0 && errno == EAGAIN)
424 return;
425
426 if (wsize >= 0) {
427 // Whether write() can return 0 is one of the greatest mysteries of UNIX.
428 // Just ignore it.
Primiano Tuccie1a28482020-08-06 14:43:54 +0200429 s_.input_written += static_cast<size_t>(wsize);
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000430 } else {
431 PERFETTO_PLOG("Subprocess write(stdin) failed");
Primiano Tuccie1a28482020-08-06 14:43:54 +0200432 s_.stdin_pipe.wr.reset();
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000433 }
434 }
Primiano Tuccie1a28482020-08-06 14:43:54 +0200435 PERFETTO_DCHECK(s_.input_written <= args.input.size());
436 if (s_.input_written == args.input.size())
437 s_.stdin_pipe.wr.reset(); // Close stdin.
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000438}
439
440void Subprocess::TryReadStdoutAndErr() {
Primiano Tuccie1a28482020-08-06 14:43:54 +0200441 if (!s_.stdouterr_pipe.rd)
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000442 return;
443 char buf[4096];
Primiano Tuccie1a28482020-08-06 14:43:54 +0200444 int64_t rsize = PERFETTO_EINTR(read(*s_.stdouterr_pipe.rd, buf, sizeof(buf)));
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000445 if (rsize < 0 && errno == EAGAIN)
446 return;
447
448 if (rsize > 0) {
Primiano Tuccie1a28482020-08-06 14:43:54 +0200449 s_.output.append(buf, static_cast<size_t>(rsize));
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000450 } else if (rsize == 0 /* EOF */) {
Primiano Tuccie1a28482020-08-06 14:43:54 +0200451 s_.stdouterr_pipe.rd.reset();
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000452 } else {
453 PERFETTO_PLOG("Subprocess read(stdout/err) failed");
Primiano Tuccie1a28482020-08-06 14:43:54 +0200454 s_.stdouterr_pipe.rd.reset();
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000455 }
456}
457
Primiano Tucciff68cac2020-08-06 18:13:17 +0200458void Subprocess::KillAndWaitForTermination(int sig_num) {
459 kill(s_.pid, sig_num ? sig_num : SIGKILL);
Primiano Tucci6d7d2542020-03-17 20:03:48 +0000460 Wait();
461}
462
463std::string Subprocess::Args::GetCmdString() const {
464 std::string str;
465 for (size_t i = 0; i < exec_cmd.size(); i++) {
466 str += i > 0 ? " \"" : "";
467 str += exec_cmd[i];
468 str += i > 0 ? "\"" : "";
469 }
470 return str;
471}
472
473} // namespace base
474} // namespace perfetto
Primiano Tucci1797cd12020-04-14 09:43:24 +0100475
476#endif // PERFETTO_HAS_SUBPROCESS()