Ninja
subprocess.h
Go to the documentation of this file.
1// Copyright 2012 Google Inc. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#ifndef NINJA_SUBPROCESS_H_
16#define NINJA_SUBPROCESS_H_
17
18#include <string>
19#include <vector>
20#include <queue>
21
22#ifdef _WIN32
23#include <windows.h>
24#else
25#include <signal.h>
26#endif
27
28// ppoll() exists on FreeBSD, but only on newer versions.
29#ifdef __FreeBSD__
30# include <sys/param.h>
31# if defined USE_PPOLL && __FreeBSD_version < 1002000
32# undef USE_PPOLL
33# endif
34#endif
35
36#include "exit_status.h"
37
38/// Subprocess wraps a single async subprocess. It is entirely
39/// passive: it expects the caller to notify it when its fds are ready
40/// for reading, as well as call Finish() to reap the child once done()
41/// is true.
42struct Subprocess {
44
45 /// Returns ExitSuccess on successful process exit, ExitInterrupted if
46 /// the process was interrupted, ExitFailure if it otherwise failed.
48
49 bool Done() const;
50
51 const std::string& GetOutput() const;
52
53 private:
54 Subprocess(bool use_console);
55 bool Start(struct SubprocessSet* set, const std::string& command);
56 void OnPipeReady();
57
58 std::string buf_;
59
60#ifdef _WIN32
61 /// Set up pipe_ as the parent-side pipe of the subprocess; return the
62 /// other end of the pipe, usable in the child process.
63 HANDLE SetupPipe(HANDLE ioport);
64
65 HANDLE child_;
66 HANDLE pipe_;
67 OVERLAPPED overlapped_;
68 char overlapped_buf_[4 << 10];
69 bool is_reading_;
70#else
71 /// The file descriptor that will be used in ppoll/pselect() for this process,
72 /// if any. Otherwise -1.
73 /// In non-console mode, this is the read-side of a pipe that was created
74 /// specifically for this subprocess. The write-side of the pipe is given to
75 /// the subprocess as combined stdout and stderr.
76 /// In console mode no pipe is created: fd_ is -1, and process termination is
77 /// detected using the SIGCHLD signal and waitpid(WNOHANG).
78 int fd_;
79 /// PID of the subprocess. Set to -1 when the subprocess is reaped.
80 pid_t pid_;
81 /// In POSIX platforms it is necessary to use waitpid(WNOHANG) to know whether
82 /// a certain subprocess has finished. This is done for terminal subprocesses.
83 /// However, this also causes the subprocess to be reaped before Finish() is
84 /// called, so we need to store the ExitStatus so that a later Finish()
85 /// invocation can return it.
87
88 /// Call waitpid() on the subprocess with the provided options and update the
89 /// pid_ and exit_status_ fields.
90 /// Return a boolean indicating whether the subprocess has indeed terminated.
91 bool TryFinish(int waitpid_options);
92#endif
94
95 friend struct SubprocessSet;
96};
97
98/// SubprocessSet runs a ppoll/pselect() loop around a set of Subprocesses.
99/// DoWork() waits for any state change in subprocesses; finished_
100/// is a queue of subprocesses as they finish.
104
105 Subprocess* Add(const std::string& command, bool use_console = false);
106 bool DoWork();
108 void Clear();
109
110 std::vector<Subprocess*> running_;
111 std::queue<Subprocess*> finished_;
112
113#ifdef _WIN32
114 static BOOL WINAPI NotifyInterrupted(DWORD dwCtrlType);
115 static HANDLE ioport_;
116#else
117 static void SetInterruptedFlag(int signum);
118 static void SigChldHandler(int signo, siginfo_t* info, void* context);
119
120 /// Store the signal number that causes the interruption.
121 /// 0 if not interruption.
122 static volatile sig_atomic_t interrupted_;
123 /// Whether ninja should quit. Set on SIGINT, SIGTERM or SIGHUP reception.
124 static bool IsInterrupted() { return interrupted_ != 0; }
125 static void HandlePendingInterruption();
126
127 /// Initialized to 0 before ppoll/pselect().
128 /// Filled to 1 by SIGCHLD handler when a child process terminates.
129 static volatile sig_atomic_t s_sigchld_received;
131
132 struct sigaction old_int_act_;
133 struct sigaction old_term_act_;
134 struct sigaction old_hup_act_;
135 struct sigaction old_chld_act_;
136 sigset_t old_mask_;
137#endif
138};
139
140#endif // NINJA_SUBPROCESS_H_
ExitStatus
Definition exit_status.h:27
void CheckConsoleProcessTerminated()
std::queue< Subprocess * > finished_
Definition subprocess.h:111
static void HandlePendingInterruption()
Subprocess * NextFinished()
static volatile sig_atomic_t interrupted_
Store the signal number that causes the interruption.
Definition subprocess.h:122
static volatile sig_atomic_t s_sigchld_received
Initialized to 0 before ppoll/pselect().
Definition subprocess.h:129
struct sigaction old_hup_act_
Definition subprocess.h:134
static void SetInterruptedFlag(int signum)
sigset_t old_mask_
Definition subprocess.h:136
struct sigaction old_chld_act_
Definition subprocess.h:135
std::vector< Subprocess * > running_
Definition subprocess.h:110
struct sigaction old_int_act_
Definition subprocess.h:132
struct sigaction old_term_act_
Definition subprocess.h:133
static void SigChldHandler(int signo, siginfo_t *info, void *context)
static bool IsInterrupted()
Whether ninja should quit. Set on SIGINT, SIGTERM or SIGHUP reception.
Definition subprocess.h:124
Subprocess * Add(const std::string &command, bool use_console=false)
Subprocess wraps a single async subprocess.
Definition subprocess.h:42
bool Start(struct SubprocessSet *set, const std::string &command)
bool TryFinish(int waitpid_options)
Call waitpid() on the subprocess with the provided options and update the pid_ and exit_status_ field...
bool Done() const
ExitStatus exit_status_
In POSIX platforms it is necessary to use waitpid(WNOHANG) to know whether a certain subprocess has f...
Definition subprocess.h:86
Subprocess(bool use_console)
int fd_
The file descriptor that will be used in ppoll/pselect() for this process, if any.
Definition subprocess.h:78
bool use_console_
Definition subprocess.h:93
ExitStatus Finish()
Returns ExitSuccess on successful process exit, ExitInterrupted if the process was interrupted,...
const std::string & GetOutput() const
friend struct SubprocessSet
Definition subprocess.h:95
std::string buf_
Definition subprocess.h:58
pid_t pid_
PID of the subprocess. Set to -1 when the subprocess is reaped.
Definition subprocess.h:80