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 {
43 ~Subprocess();
44
45 /// Returns ExitSuccess on successful process exit, ExitInterrupted if
46 /// the process was interrupted, ExitFailure if it otherwise failed.
47 ExitStatus Finish();
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 int fd_;
72 pid_t pid_;
73#endif
74 bool use_console_;
75
76 friend struct SubprocessSet;
77};
78
79/// SubprocessSet runs a ppoll/pselect() loop around a set of Subprocesses.
80/// DoWork() waits for any state change in subprocesses; finished_
81/// is a queue of subprocesses as they finish.
82struct SubprocessSet {
83 SubprocessSet();
84 ~SubprocessSet();
85
86 Subprocess* Add(const std::string& command, bool use_console = false);
87 bool DoWork();
88 Subprocess* NextFinished();
89 void Clear();
90
91 std::vector<Subprocess*> running_;
92 std::queue<Subprocess*> finished_;
93
94#ifdef _WIN32
95 static BOOL WINAPI NotifyInterrupted(DWORD dwCtrlType);
96 static HANDLE ioport_;
97#else
98 static void SetInterruptedFlag(int signum);
99 static void HandlePendingInterruption();
100 /// Store the signal number that causes the interruption.
101 /// 0 if not interruption.
102 static int interrupted_;
103
104 static bool IsInterrupted() { return interrupted_ != 0; }
105
106 struct sigaction old_int_act_;
107 struct sigaction old_term_act_;
108 struct sigaction old_hup_act_;
109 sigset_t old_mask_;
110#endif
111};
112
113#endif // NINJA_SUBPROCESS_H_
114