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