• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
42 struct 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.
82 struct 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 
IsInterruptedSubprocessSet104   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