1695b41eeSopenharmony_ci// Copyright 2012 Google Inc. All Rights Reserved.
2695b41eeSopenharmony_ci//
3695b41eeSopenharmony_ci// Licensed under the Apache License, Version 2.0 (the "License");
4695b41eeSopenharmony_ci// you may not use this file except in compliance with the License.
5695b41eeSopenharmony_ci// You may obtain a copy of the License at
6695b41eeSopenharmony_ci//
7695b41eeSopenharmony_ci//     http://www.apache.org/licenses/LICENSE-2.0
8695b41eeSopenharmony_ci//
9695b41eeSopenharmony_ci// Unless required by applicable law or agreed to in writing, software
10695b41eeSopenharmony_ci// distributed under the License is distributed on an "AS IS" BASIS,
11695b41eeSopenharmony_ci// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12695b41eeSopenharmony_ci// See the License for the specific language governing permissions and
13695b41eeSopenharmony_ci// limitations under the License.
14695b41eeSopenharmony_ci
15695b41eeSopenharmony_ci#include "subprocess.h"
16695b41eeSopenharmony_ci
17695b41eeSopenharmony_ci#include <sys/select.h>
18695b41eeSopenharmony_ci#include <assert.h>
19695b41eeSopenharmony_ci#include <errno.h>
20695b41eeSopenharmony_ci#include <fcntl.h>
21695b41eeSopenharmony_ci#include <unistd.h>
22695b41eeSopenharmony_ci#include <stdio.h>
23695b41eeSopenharmony_ci#include <string.h>
24695b41eeSopenharmony_ci#include <sys/wait.h>
25695b41eeSopenharmony_ci#include <spawn.h>
26695b41eeSopenharmony_ci
27695b41eeSopenharmony_ci#if defined(USE_PPOLL)
28695b41eeSopenharmony_ci#include <poll.h>
29695b41eeSopenharmony_ci#else
30695b41eeSopenharmony_ci#include <sys/select.h>
31695b41eeSopenharmony_ci#endif
32695b41eeSopenharmony_ci
33695b41eeSopenharmony_ciextern char** environ;
34695b41eeSopenharmony_ci
35695b41eeSopenharmony_ci#include "util.h"
36695b41eeSopenharmony_ci
37695b41eeSopenharmony_ciusing namespace std;
38695b41eeSopenharmony_ci
39695b41eeSopenharmony_ciSubprocess::Subprocess(bool use_console) : fd_(-1), pid_(-1),
40695b41eeSopenharmony_ci                                           use_console_(use_console) {
41695b41eeSopenharmony_ci}
42695b41eeSopenharmony_ci
43695b41eeSopenharmony_ciSubprocess::~Subprocess() {
44695b41eeSopenharmony_ci  if (fd_ >= 0)
45695b41eeSopenharmony_ci    close(fd_);
46695b41eeSopenharmony_ci  // Reap child if forgotten.
47695b41eeSopenharmony_ci  if (pid_ != -1)
48695b41eeSopenharmony_ci    Finish();
49695b41eeSopenharmony_ci}
50695b41eeSopenharmony_ci
51695b41eeSopenharmony_cibool Subprocess::Start(SubprocessSet* set, const string& command) {
52695b41eeSopenharmony_ci  int output_pipe[2];
53695b41eeSopenharmony_ci  if (pipe(output_pipe) < 0)
54695b41eeSopenharmony_ci    Fatal("pipe: %s", strerror(errno));
55695b41eeSopenharmony_ci  fd_ = output_pipe[0];
56695b41eeSopenharmony_ci#if !defined(USE_PPOLL)
57695b41eeSopenharmony_ci  // If available, we use ppoll in DoWork(); otherwise we use pselect
58695b41eeSopenharmony_ci  // and so must avoid overly-large FDs.
59695b41eeSopenharmony_ci  if (fd_ >= static_cast<int>(FD_SETSIZE))
60695b41eeSopenharmony_ci    Fatal("pipe: %s", strerror(EMFILE));
61695b41eeSopenharmony_ci#endif  // !USE_PPOLL
62695b41eeSopenharmony_ci  SetCloseOnExec(fd_);
63695b41eeSopenharmony_ci
64695b41eeSopenharmony_ci  posix_spawn_file_actions_t action;
65695b41eeSopenharmony_ci  int err = posix_spawn_file_actions_init(&action);
66695b41eeSopenharmony_ci  if (err != 0)
67695b41eeSopenharmony_ci    Fatal("posix_spawn_file_actions_init: %s", strerror(err));
68695b41eeSopenharmony_ci
69695b41eeSopenharmony_ci  err = posix_spawn_file_actions_addclose(&action, output_pipe[0]);
70695b41eeSopenharmony_ci  if (err != 0)
71695b41eeSopenharmony_ci    Fatal("posix_spawn_file_actions_addclose: %s", strerror(err));
72695b41eeSopenharmony_ci
73695b41eeSopenharmony_ci  posix_spawnattr_t attr;
74695b41eeSopenharmony_ci  err = posix_spawnattr_init(&attr);
75695b41eeSopenharmony_ci  if (err != 0)
76695b41eeSopenharmony_ci    Fatal("posix_spawnattr_init: %s", strerror(err));
77695b41eeSopenharmony_ci
78695b41eeSopenharmony_ci  short flags = 0;
79695b41eeSopenharmony_ci
80695b41eeSopenharmony_ci  flags |= POSIX_SPAWN_SETSIGMASK;
81695b41eeSopenharmony_ci  err = posix_spawnattr_setsigmask(&attr, &set->old_mask_);
82695b41eeSopenharmony_ci  if (err != 0)
83695b41eeSopenharmony_ci    Fatal("posix_spawnattr_setsigmask: %s", strerror(err));
84695b41eeSopenharmony_ci  // Signals which are set to be caught in the calling process image are set to
85695b41eeSopenharmony_ci  // default action in the new process image, so no explicit
86695b41eeSopenharmony_ci  // POSIX_SPAWN_SETSIGDEF parameter is needed.
87695b41eeSopenharmony_ci
88695b41eeSopenharmony_ci  if (!use_console_) {
89695b41eeSopenharmony_ci    // Put the child in its own process group, so ctrl-c won't reach it.
90695b41eeSopenharmony_ci    flags |= POSIX_SPAWN_SETPGROUP;
91695b41eeSopenharmony_ci    // No need to posix_spawnattr_setpgroup(&attr, 0), it's the default.
92695b41eeSopenharmony_ci
93695b41eeSopenharmony_ci    // Open /dev/null over stdin.
94695b41eeSopenharmony_ci    err = posix_spawn_file_actions_addopen(&action, 0, "/dev/null", O_RDONLY,
95695b41eeSopenharmony_ci          0);
96695b41eeSopenharmony_ci    if (err != 0) {
97695b41eeSopenharmony_ci      Fatal("posix_spawn_file_actions_addopen: %s", strerror(err));
98695b41eeSopenharmony_ci    }
99695b41eeSopenharmony_ci
100695b41eeSopenharmony_ci    err = posix_spawn_file_actions_adddup2(&action, output_pipe[1], 1);
101695b41eeSopenharmony_ci    if (err != 0)
102695b41eeSopenharmony_ci      Fatal("posix_spawn_file_actions_adddup2: %s", strerror(err));
103695b41eeSopenharmony_ci    err = posix_spawn_file_actions_adddup2(&action, output_pipe[1], 2);
104695b41eeSopenharmony_ci    if (err != 0)
105695b41eeSopenharmony_ci      Fatal("posix_spawn_file_actions_adddup2: %s", strerror(err));
106695b41eeSopenharmony_ci    err = posix_spawn_file_actions_addclose(&action, output_pipe[1]);
107695b41eeSopenharmony_ci    if (err != 0)
108695b41eeSopenharmony_ci      Fatal("posix_spawn_file_actions_addclose: %s", strerror(err));
109695b41eeSopenharmony_ci    // In the console case, output_pipe is still inherited by the child and
110695b41eeSopenharmony_ci    // closed when the subprocess finishes, which then notifies ninja.
111695b41eeSopenharmony_ci  }
112695b41eeSopenharmony_ci#ifdef POSIX_SPAWN_USEVFORK
113695b41eeSopenharmony_ci  flags |= POSIX_SPAWN_USEVFORK;
114695b41eeSopenharmony_ci#endif
115695b41eeSopenharmony_ci
116695b41eeSopenharmony_ci  err = posix_spawnattr_setflags(&attr, flags);
117695b41eeSopenharmony_ci  if (err != 0)
118695b41eeSopenharmony_ci    Fatal("posix_spawnattr_setflags: %s", strerror(err));
119695b41eeSopenharmony_ci
120695b41eeSopenharmony_ci  const char* spawned_args[] = { "/bin/sh", "-c", command.c_str(), NULL };
121695b41eeSopenharmony_ci  err = posix_spawn(&pid_, "/bin/sh", &action, &attr,
122695b41eeSopenharmony_ci        const_cast<char**>(spawned_args), environ);
123695b41eeSopenharmony_ci  if (err != 0)
124695b41eeSopenharmony_ci    Fatal("posix_spawn: %s", strerror(err));
125695b41eeSopenharmony_ci
126695b41eeSopenharmony_ci  err = posix_spawnattr_destroy(&attr);
127695b41eeSopenharmony_ci  if (err != 0)
128695b41eeSopenharmony_ci    Fatal("posix_spawnattr_destroy: %s", strerror(err));
129695b41eeSopenharmony_ci  err = posix_spawn_file_actions_destroy(&action);
130695b41eeSopenharmony_ci  if (err != 0)
131695b41eeSopenharmony_ci    Fatal("posix_spawn_file_actions_destroy: %s", strerror(err));
132695b41eeSopenharmony_ci
133695b41eeSopenharmony_ci  close(output_pipe[1]);
134695b41eeSopenharmony_ci  return true;
135695b41eeSopenharmony_ci}
136695b41eeSopenharmony_ci
137695b41eeSopenharmony_civoid Subprocess::OnPipeReady() {
138695b41eeSopenharmony_ci  char buf[4 << 10];
139695b41eeSopenharmony_ci  ssize_t len = read(fd_, buf, sizeof(buf));
140695b41eeSopenharmony_ci  if (len > 0) {
141695b41eeSopenharmony_ci    buf_.append(buf, len);
142695b41eeSopenharmony_ci  } else {
143695b41eeSopenharmony_ci    if (len < 0)
144695b41eeSopenharmony_ci      Fatal("read: %s", strerror(errno));
145695b41eeSopenharmony_ci    close(fd_);
146695b41eeSopenharmony_ci    fd_ = -1;
147695b41eeSopenharmony_ci  }
148695b41eeSopenharmony_ci}
149695b41eeSopenharmony_ci
150695b41eeSopenharmony_ciExitStatus Subprocess::Finish() {
151695b41eeSopenharmony_ci  assert(pid_ != -1);
152695b41eeSopenharmony_ci  int status;
153695b41eeSopenharmony_ci  if (waitpid(pid_, &status, 0) < 0)
154695b41eeSopenharmony_ci    Fatal("waitpid(%d): %s", pid_, strerror(errno));
155695b41eeSopenharmony_ci  pid_ = -1;
156695b41eeSopenharmony_ci
157695b41eeSopenharmony_ci#ifdef _AIX
158695b41eeSopenharmony_ci  if (WIFEXITED(status) && WEXITSTATUS(status) & 0x80) {
159695b41eeSopenharmony_ci    // Map the shell's exit code used for signal failure (128 + signal) to the
160695b41eeSopenharmony_ci    // status code expected by AIX WIFSIGNALED and WTERMSIG macros which, unlike
161695b41eeSopenharmony_ci    // other systems, uses a different bit layout.
162695b41eeSopenharmony_ci    int signal = WEXITSTATUS(status) & 0x7f;
163695b41eeSopenharmony_ci    status = (signal << 16) | signal;
164695b41eeSopenharmony_ci  }
165695b41eeSopenharmony_ci#endif
166695b41eeSopenharmony_ci
167695b41eeSopenharmony_ci  if (WIFEXITED(status)) {
168695b41eeSopenharmony_ci    int exit = WEXITSTATUS(status);
169695b41eeSopenharmony_ci    if (exit == 0)
170695b41eeSopenharmony_ci      return ExitSuccess;
171695b41eeSopenharmony_ci  } else if (WIFSIGNALED(status)) {
172695b41eeSopenharmony_ci    if (WTERMSIG(status) == SIGINT || WTERMSIG(status) == SIGTERM
173695b41eeSopenharmony_ci        || WTERMSIG(status) == SIGHUP)
174695b41eeSopenharmony_ci      return ExitInterrupted;
175695b41eeSopenharmony_ci  }
176695b41eeSopenharmony_ci  return ExitFailure;
177695b41eeSopenharmony_ci}
178695b41eeSopenharmony_ci
179695b41eeSopenharmony_cibool Subprocess::Done() const {
180695b41eeSopenharmony_ci  return fd_ == -1;
181695b41eeSopenharmony_ci}
182695b41eeSopenharmony_ci
183695b41eeSopenharmony_ciconst string& Subprocess::GetOutput() const {
184695b41eeSopenharmony_ci  return buf_;
185695b41eeSopenharmony_ci}
186695b41eeSopenharmony_ci
187695b41eeSopenharmony_ciint SubprocessSet::interrupted_;
188695b41eeSopenharmony_ci
189695b41eeSopenharmony_civoid SubprocessSet::SetInterruptedFlag(int signum) {
190695b41eeSopenharmony_ci  interrupted_ = signum;
191695b41eeSopenharmony_ci}
192695b41eeSopenharmony_ci
193695b41eeSopenharmony_civoid SubprocessSet::HandlePendingInterruption() {
194695b41eeSopenharmony_ci  sigset_t pending;
195695b41eeSopenharmony_ci  sigemptyset(&pending);
196695b41eeSopenharmony_ci  if (sigpending(&pending) == -1) {
197695b41eeSopenharmony_ci    perror("ninja: sigpending");
198695b41eeSopenharmony_ci    return;
199695b41eeSopenharmony_ci  }
200695b41eeSopenharmony_ci  if (sigismember(&pending, SIGINT))
201695b41eeSopenharmony_ci    interrupted_ = SIGINT;
202695b41eeSopenharmony_ci  else if (sigismember(&pending, SIGTERM))
203695b41eeSopenharmony_ci    interrupted_ = SIGTERM;
204695b41eeSopenharmony_ci  else if (sigismember(&pending, SIGHUP))
205695b41eeSopenharmony_ci    interrupted_ = SIGHUP;
206695b41eeSopenharmony_ci}
207695b41eeSopenharmony_ci
208695b41eeSopenharmony_ciSubprocessSet::SubprocessSet() {
209695b41eeSopenharmony_ci  sigset_t set;
210695b41eeSopenharmony_ci  sigemptyset(&set);
211695b41eeSopenharmony_ci  sigaddset(&set, SIGINT);
212695b41eeSopenharmony_ci  sigaddset(&set, SIGTERM);
213695b41eeSopenharmony_ci  sigaddset(&set, SIGHUP);
214695b41eeSopenharmony_ci  if (sigprocmask(SIG_BLOCK, &set, &old_mask_) < 0)
215695b41eeSopenharmony_ci    Fatal("sigprocmask: %s", strerror(errno));
216695b41eeSopenharmony_ci
217695b41eeSopenharmony_ci  struct sigaction act;
218695b41eeSopenharmony_ci  memset(&act, 0, sizeof(act));
219695b41eeSopenharmony_ci  act.sa_handler = SetInterruptedFlag;
220695b41eeSopenharmony_ci  if (sigaction(SIGINT, &act, &old_int_act_) < 0)
221695b41eeSopenharmony_ci    Fatal("sigaction: %s", strerror(errno));
222695b41eeSopenharmony_ci  if (sigaction(SIGTERM, &act, &old_term_act_) < 0)
223695b41eeSopenharmony_ci    Fatal("sigaction: %s", strerror(errno));
224695b41eeSopenharmony_ci  if (sigaction(SIGHUP, &act, &old_hup_act_) < 0)
225695b41eeSopenharmony_ci    Fatal("sigaction: %s", strerror(errno));
226695b41eeSopenharmony_ci}
227695b41eeSopenharmony_ci
228695b41eeSopenharmony_ciSubprocessSet::~SubprocessSet() {
229695b41eeSopenharmony_ci  Clear();
230695b41eeSopenharmony_ci
231695b41eeSopenharmony_ci  if (sigaction(SIGINT, &old_int_act_, 0) < 0)
232695b41eeSopenharmony_ci    Fatal("sigaction: %s", strerror(errno));
233695b41eeSopenharmony_ci  if (sigaction(SIGTERM, &old_term_act_, 0) < 0)
234695b41eeSopenharmony_ci    Fatal("sigaction: %s", strerror(errno));
235695b41eeSopenharmony_ci  if (sigaction(SIGHUP, &old_hup_act_, 0) < 0)
236695b41eeSopenharmony_ci    Fatal("sigaction: %s", strerror(errno));
237695b41eeSopenharmony_ci  if (sigprocmask(SIG_SETMASK, &old_mask_, 0) < 0)
238695b41eeSopenharmony_ci    Fatal("sigprocmask: %s", strerror(errno));
239695b41eeSopenharmony_ci}
240695b41eeSopenharmony_ci
241695b41eeSopenharmony_ciSubprocess *SubprocessSet::Add(const string& command, bool use_console) {
242695b41eeSopenharmony_ci  Subprocess *subprocess = new Subprocess(use_console);
243695b41eeSopenharmony_ci  if (!subprocess->Start(this, command)) {
244695b41eeSopenharmony_ci    delete subprocess;
245695b41eeSopenharmony_ci    return 0;
246695b41eeSopenharmony_ci  }
247695b41eeSopenharmony_ci  running_.push_back(subprocess);
248695b41eeSopenharmony_ci  return subprocess;
249695b41eeSopenharmony_ci}
250695b41eeSopenharmony_ci
251695b41eeSopenharmony_ci#ifdef USE_PPOLL
252695b41eeSopenharmony_cibool SubprocessSet::DoWork() {
253695b41eeSopenharmony_ci  vector<pollfd> fds;
254695b41eeSopenharmony_ci  nfds_t nfds = 0;
255695b41eeSopenharmony_ci
256695b41eeSopenharmony_ci  for (vector<Subprocess*>::iterator i = running_.begin();
257695b41eeSopenharmony_ci       i != running_.end(); ++i) {
258695b41eeSopenharmony_ci    int fd = (*i)->fd_;
259695b41eeSopenharmony_ci    if (fd < 0)
260695b41eeSopenharmony_ci      continue;
261695b41eeSopenharmony_ci    pollfd pfd = { fd, POLLIN | POLLPRI, 0 };
262695b41eeSopenharmony_ci    fds.push_back(pfd);
263695b41eeSopenharmony_ci    ++nfds;
264695b41eeSopenharmony_ci  }
265695b41eeSopenharmony_ci
266695b41eeSopenharmony_ci  interrupted_ = 0;
267695b41eeSopenharmony_ci  int ret = ppoll(&fds.front(), nfds, NULL, &old_mask_);
268695b41eeSopenharmony_ci  if (ret == -1) {
269695b41eeSopenharmony_ci    if (errno != EINTR) {
270695b41eeSopenharmony_ci      perror("ninja: ppoll");
271695b41eeSopenharmony_ci      return false;
272695b41eeSopenharmony_ci    }
273695b41eeSopenharmony_ci    return IsInterrupted();
274695b41eeSopenharmony_ci  }
275695b41eeSopenharmony_ci
276695b41eeSopenharmony_ci  HandlePendingInterruption();
277695b41eeSopenharmony_ci  if (IsInterrupted())
278695b41eeSopenharmony_ci    return true;
279695b41eeSopenharmony_ci
280695b41eeSopenharmony_ci  nfds_t cur_nfd = 0;
281695b41eeSopenharmony_ci  for (vector<Subprocess*>::iterator i = running_.begin();
282695b41eeSopenharmony_ci       i != running_.end(); ) {
283695b41eeSopenharmony_ci    int fd = (*i)->fd_;
284695b41eeSopenharmony_ci    if (fd < 0)
285695b41eeSopenharmony_ci      continue;
286695b41eeSopenharmony_ci    assert(fd == fds[cur_nfd].fd);
287695b41eeSopenharmony_ci    if (fds[cur_nfd++].revents) {
288695b41eeSopenharmony_ci      (*i)->OnPipeReady();
289695b41eeSopenharmony_ci      if ((*i)->Done()) {
290695b41eeSopenharmony_ci        finished_.push(*i);
291695b41eeSopenharmony_ci        i = running_.erase(i);
292695b41eeSopenharmony_ci        continue;
293695b41eeSopenharmony_ci      }
294695b41eeSopenharmony_ci    }
295695b41eeSopenharmony_ci    ++i;
296695b41eeSopenharmony_ci  }
297695b41eeSopenharmony_ci
298695b41eeSopenharmony_ci  return IsInterrupted();
299695b41eeSopenharmony_ci}
300695b41eeSopenharmony_ci
301695b41eeSopenharmony_ci#else  // !defined(USE_PPOLL)
302695b41eeSopenharmony_cibool SubprocessSet::DoWork() {
303695b41eeSopenharmony_ci  fd_set set;
304695b41eeSopenharmony_ci  int nfds = 0;
305695b41eeSopenharmony_ci  FD_ZERO(&set);
306695b41eeSopenharmony_ci
307695b41eeSopenharmony_ci  for (vector<Subprocess*>::iterator i = running_.begin();
308695b41eeSopenharmony_ci       i != running_.end(); ++i) {
309695b41eeSopenharmony_ci    int fd = (*i)->fd_;
310695b41eeSopenharmony_ci    if (fd >= 0) {
311695b41eeSopenharmony_ci      FD_SET(fd, &set);
312695b41eeSopenharmony_ci      if (nfds < fd+1)
313695b41eeSopenharmony_ci        nfds = fd+1;
314695b41eeSopenharmony_ci    }
315695b41eeSopenharmony_ci  }
316695b41eeSopenharmony_ci
317695b41eeSopenharmony_ci  interrupted_ = 0;
318695b41eeSopenharmony_ci  int ret = pselect(nfds, &set, 0, 0, 0, &old_mask_);
319695b41eeSopenharmony_ci  if (ret == -1) {
320695b41eeSopenharmony_ci    if (errno != EINTR) {
321695b41eeSopenharmony_ci      perror("ninja: pselect");
322695b41eeSopenharmony_ci      return false;
323695b41eeSopenharmony_ci    }
324695b41eeSopenharmony_ci    return IsInterrupted();
325695b41eeSopenharmony_ci  }
326695b41eeSopenharmony_ci
327695b41eeSopenharmony_ci  HandlePendingInterruption();
328695b41eeSopenharmony_ci  if (IsInterrupted())
329695b41eeSopenharmony_ci    return true;
330695b41eeSopenharmony_ci
331695b41eeSopenharmony_ci  for (vector<Subprocess*>::iterator i = running_.begin();
332695b41eeSopenharmony_ci       i != running_.end(); ) {
333695b41eeSopenharmony_ci    int fd = (*i)->fd_;
334695b41eeSopenharmony_ci    if (fd >= 0 && FD_ISSET(fd, &set)) {
335695b41eeSopenharmony_ci      (*i)->OnPipeReady();
336695b41eeSopenharmony_ci      if ((*i)->Done()) {
337695b41eeSopenharmony_ci        finished_.push(*i);
338695b41eeSopenharmony_ci        i = running_.erase(i);
339695b41eeSopenharmony_ci        continue;
340695b41eeSopenharmony_ci      }
341695b41eeSopenharmony_ci    }
342695b41eeSopenharmony_ci    ++i;
343695b41eeSopenharmony_ci  }
344695b41eeSopenharmony_ci
345695b41eeSopenharmony_ci  return IsInterrupted();
346695b41eeSopenharmony_ci}
347695b41eeSopenharmony_ci#endif  // !defined(USE_PPOLL)
348695b41eeSopenharmony_ci
349695b41eeSopenharmony_ciSubprocess* SubprocessSet::NextFinished() {
350695b41eeSopenharmony_ci  if (finished_.empty())
351695b41eeSopenharmony_ci    return NULL;
352695b41eeSopenharmony_ci  Subprocess* subproc = finished_.front();
353695b41eeSopenharmony_ci  finished_.pop();
354695b41eeSopenharmony_ci  return subproc;
355695b41eeSopenharmony_ci}
356695b41eeSopenharmony_ci
357695b41eeSopenharmony_civoid SubprocessSet::Clear() {
358695b41eeSopenharmony_ci  for (vector<Subprocess*>::iterator i = running_.begin();
359695b41eeSopenharmony_ci       i != running_.end(); ++i)
360695b41eeSopenharmony_ci    // Since the foreground process is in our process group, it will receive
361695b41eeSopenharmony_ci    // the interruption signal (i.e. SIGINT or SIGTERM) at the same time as us.
362695b41eeSopenharmony_ci    if (!(*i)->use_console_)
363695b41eeSopenharmony_ci      kill(-(*i)->pid_, interrupted_);
364695b41eeSopenharmony_ci  for (vector<Subprocess*>::iterator i = running_.begin();
365695b41eeSopenharmony_ci       i != running_.end(); ++i)
366695b41eeSopenharmony_ci    delete *i;
367695b41eeSopenharmony_ci  running_.clear();
368695b41eeSopenharmony_ci}
369