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 using namespace std; 22 23 #ifdef _WIN32 24 #include <windows.h> 25 #else 26 #include <signal.h> 27 #endif 28 29 // ppoll() exists on FreeBSD, but only on newer versions. 30 #ifdef __FreeBSD__ 31 # include <sys/param.h> 32 # if defined USE_PPOLL && __FreeBSD_version < 1002000 33 # undef USE_PPOLL 34 # endif 35 #endif 36 37 #include "exit_status.h" 38 39 /// Subprocess wraps a single async subprocess. It is entirely 40 /// passive: it expects the caller to notify it when its fds are ready 41 /// for reading, as well as call Finish() to reap the child once done() 42 /// is true. 43 struct Subprocess { 44 ~Subprocess(); 45 46 /// Returns ExitSuccess on successful process exit, ExitInterrupted if 47 /// the process was interrupted, ExitFailure if it otherwise failed. 48 ExitStatus Finish(); 49 50 bool Done() const; 51 52 const string& GetOutput() const; 53 54 private: 55 Subprocess(bool use_console); 56 bool Start(struct SubprocessSet* set, const string& command); 57 void OnPipeReady(); 58 59 string buf_; 60 61 #ifdef _WIN32 62 /// Set up pipe_ as the parent-side pipe of the subprocess; return the 63 /// other end of the pipe, usable in the child process. 64 HANDLE SetupPipe(HANDLE ioport); 65 66 HANDLE child_; 67 HANDLE pipe_; 68 OVERLAPPED overlapped_; 69 char overlapped_buf_[4 << 10]; 70 bool is_reading_; 71 #else 72 int fd_; 73 pid_t pid_; 74 #endif 75 bool use_console_; 76 77 friend struct SubprocessSet; 78 }; 79 80 /// SubprocessSet runs a ppoll/pselect() loop around a set of Subprocesses. 81 /// DoWork() waits for any state change in subprocesses; finished_ 82 /// is a queue of subprocesses as they finish. 83 struct SubprocessSet { 84 SubprocessSet(); 85 ~SubprocessSet(); 86 87 Subprocess* Add(const string& command, bool use_console = false); 88 bool DoWork(); 89 Subprocess* NextFinished(); 90 void Clear(); 91 92 vector<Subprocess*> running_; 93 queue<Subprocess*> finished_; 94 95 #ifdef _WIN32 96 static BOOL WINAPI NotifyInterrupted(DWORD dwCtrlType); 97 static HANDLE ioport_; 98 #else 99 static void SetInterruptedFlag(int signum); 100 static void HandlePendingInterruption(); 101 /// Store the signal number that causes the interruption. 102 /// 0 if not interruption. 103 static int interrupted_; 104 IsInterruptedSubprocessSet105 static bool IsInterrupted() { return interrupted_ != 0; } 106 107 struct sigaction old_int_act_; 108 struct sigaction old_term_act_; 109 struct sigaction old_hup_act_; 110 sigset_t old_mask_; 111 #endif 112 }; 113 114 #endif // NINJA_SUBPROCESS_H_ 115