ninja_build/
subprocess.rs

1// Copyright 2012 Google Inc. All Rights Reserved.
2// Copyright 2017 The Ninja-rs Project Developers. All Rights Reserved.
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//     http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use std::collections::{VecDeque, HashMap};
17use std::cell::Cell;
18#[cfg(unix)]
19use super::utils::set_close_on_exec;
20
21use super::exit_status::ExitStatus;
22
23#[cfg(windows)]
24struct SubprocessOs {
25    pub child: ::winapi::HANDLE,
26    pub pipe: ::winapi::HANDLE,
27    pub overlapped: ::winapi::OVERLAPPED,
28    pub overlapped_buf: [u8; 4096],
29    pub is_reading: bool,
30}
31
32#[cfg(windows)]
33impl Default for SubprocessOs {
34    fn default() -> Self {
35        unsafe { ::std::mem::zeroed() }
36    }
37}
38
39
40#[cfg(unix)]
41#[derive(Default)]
42struct SubprocessOs {
43    pub fd: Option<::libc::c_int>,
44    pub pid: Option<::libc::pid_t>,
45}
46
47/// Subprocess wraps a single async subprocess.  It is entirely
48/// passive: it expects the caller to notify it when its fds are ready
49/// for reading, as well as call Finish() to reap the child once done()
50/// is true.
51pub struct Subprocess {
52    use_console: bool,
53    buf: Vec<u8>,
54    extra: Box<SubprocessOs>,
55}
56
57impl Subprocess {
58    // always boxed to make sure pointer to self is not changed.
59    pub(super) fn new(use_console: bool) -> Box<Self> {
60        Box::new(Subprocess {
61            use_console,
62            buf: Vec::new(),
63            extra: Default::default(),
64        })
65    }
66
67    pub fn output(&self) -> &[u8] {
68        &self.buf
69    }
70}
71
72#[cfg(windows)]
73impl Drop for Subprocess {
74    fn drop(&mut self) {
75        use winapi;
76        use errno;
77        use kernel32;
78
79        if !self.extra.pipe.is_null() {
80            if unsafe { kernel32::CloseHandle(self.extra.pipe) } == winapi::FALSE {
81                fatal!("CloseHandle: {}", errno::errno());
82            }
83        }
84
85        // Reap child if forgotten.
86        if self.exist() {
87            self.finish();
88        }
89    }
90}
91
92#[cfg(windows)]
93impl Subprocess {
94    pub(super) fn exist(&self) -> bool {
95        !self.extra.child.is_null()
96    }
97
98    pub(super) fn start<T>(&mut self, set: &mut SubprocessSet<T>, command: &[u8]) -> bool {
99        use winapi;
100        use kernel32;
101        use std::ptr::null_mut;
102        use std::mem::{zeroed, size_of};
103
104        let child_pipe = self.setup_pipe(set.extra.ioport());
105
106        let mut security_attributes = unsafe { zeroed::<winapi::SECURITY_ATTRIBUTES>() };
107        security_attributes.nLength = size_of::<winapi::SECURITY_ATTRIBUTES>() as _;
108        security_attributes.bInheritHandle = winapi::TRUE;
109
110        let nul_name = wstrz!("NUL");
111
112        let nul = unsafe {
113            kernel32::CreateFileW(
114                nul_name.as_ptr(),
115                winapi::GENERIC_READ,
116                winapi::FILE_SHARE_READ | winapi::FILE_SHARE_WRITE | winapi::FILE_SHARE_DELETE,
117                &mut security_attributes as _,
118                winapi::OPEN_EXISTING,
119                0,
120                null_mut(),
121            )
122        };
123
124        if nul == winapi::INVALID_HANDLE_VALUE {
125            fatal!("couldn't open nul");
126        }
127
128        let mut startup_info = unsafe { zeroed::<winapi::STARTUPINFOW>() };
129        startup_info.cb = size_of::<winapi::STARTUPINFOW>() as _;
130        if !self.use_console {
131            startup_info.dwFlags = winapi::STARTF_USESTDHANDLES;
132            startup_info.hStdInput = nul;
133            startup_info.hStdOutput = child_pipe;
134            startup_info.hStdError = child_pipe;
135        }
136
137        // In the console case, child_pipe is still inherited by the child and closed
138        // when the subprocess finishes, which then notifies ninja.
139        let mut process_info = unsafe { zeroed::<winapi::PROCESS_INFORMATION>() };
140
141        // Ninja handles ctrl-c, except for subprocesses in console pools.
142        let process_flags = if self.use_console {
143            0
144        } else {
145            winapi::CREATE_NEW_PROCESS_GROUP
146        };
147
148        // Do not prepend 'cmd /c' on Windows, this breaks command
149        // lines greater than 8,191 chars.
150        let cmd_unicode = ::std::str::from_utf8(command);
151        let create_process_result = match &cmd_unicode {
152            &Err(_) => Err(None),
153            &Ok(ref cmd_unicode) => {
154                if let Ok(cmd) = ::widestring::WideCString::from_str(cmd_unicode) {
155                    let mut cmd = cmd.into_vec();
156                    if unsafe {
157                        kernel32::CreateProcessW(
158                            null_mut(),
159                            cmd.as_mut_ptr(),
160                            null_mut(),
161                            null_mut(),
162                            winapi::TRUE,
163                            process_flags,
164                            null_mut(),
165                            null_mut(),
166                            &mut startup_info as _,
167                            &mut process_info as _,
168                        )
169                    } != winapi::FALSE
170                    {
171                        Ok(())
172                    } else {
173                        Err(Some(unsafe { kernel32::GetLastError() }))
174                    }
175                } else {
176                    Err(None)
177                }
178            }
179        };
180
181        if !child_pipe.is_null() {
182            unsafe { kernel32::CloseHandle(child_pipe) };
183        }
184
185        unsafe { kernel32::CloseHandle(nul) };
186
187        match create_process_result {
188            Ok(()) => {
189                unsafe { kernel32::CloseHandle(process_info.hThread) };
190                self.extra.child = process_info.hProcess;
191                true
192            }
193            Err(e @ Some(winapi::ERROR_FILE_NOT_FOUND)) |
194            Err(e @ None) => {
195                // File (program) not found error is treated as a normal build
196                // action failure.
197                unsafe { kernel32::CloseHandle(self.extra.pipe) };
198                self.extra.pipe = null_mut();
199                // child_ is already NULL;
200                self.buf = if e.is_some() {
201                    b"CreateProcess failed: The system cannot find the file specified.\n"
202                        .as_ref()
203                        .to_owned()
204                } else {
205                    b"CreateProcess failed: The command is not valid UTF-8 string.\n"
206                        .as_ref()
207                        .to_owned()
208                };
209                true
210            }
211            Err(Some(e)) => fatal!("CreateProcess : {}", ::errno::Errno(e as _)),
212        }
213    }
214
215
216    /// Set up pipe_ as the parent-side pipe of the subprocess; return the
217    /// other end of the pipe, usable in the child process.
218    fn setup_pipe(&mut self, ioport: ::winapi::HANDLE) -> ::winapi::HANDLE {
219        use winapi;
220        use kernel32;
221        use errno;
222        use std::mem::zeroed;
223        use std::ptr::null_mut;
224        use widestring::WideCString;
225        let pipe_name = format!(
226            "\\\\.\\pipe\\ninja_pid{}_sp{:p}",
227            unsafe { kernel32::GetCurrentProcessId() },
228            self
229        );
230
231        let pipe_name = WideCString::from_str(pipe_name).unwrap().into_vec();
232
233        self.extra.pipe = unsafe {
234            kernel32::CreateNamedPipeW(
235                pipe_name.as_ptr(),
236                winapi::PIPE_ACCESS_INBOUND | winapi::FILE_FLAG_OVERLAPPED,
237                winapi::PIPE_TYPE_BYTE,
238                winapi::PIPE_UNLIMITED_INSTANCES,
239                0,
240                0,
241                winapi::INFINITE,
242                null_mut(),
243            )
244        };
245
246        if self.extra.pipe == winapi::INVALID_HANDLE_VALUE {
247            fatal!("CreateNamedPipe : {}", errno::errno());
248        }
249
250        let create_port_result = unsafe {
251            kernel32::CreateIoCompletionPort(
252                self.extra.pipe,
253                ioport,
254                self as *mut _ as usize as _,
255                0,
256            )
257        };
258        if create_port_result.is_null() {
259            fatal!("CreateIoCompletionPort : {}", errno::errno());
260        }
261
262        self.extra.overlapped = unsafe { zeroed() };
263        if unsafe {
264            kernel32::ConnectNamedPipe(self.extra.pipe, &mut self.extra.overlapped as _)
265        } == winapi::FALSE &&
266            unsafe { kernel32::GetLastError() } != winapi::ERROR_IO_PENDING
267        {
268            fatal!("ConnectNamedPipe : {}", errno::errno());
269        }
270
271        // Get the write end of the pipe as a handle inheritable across processes.
272        let output_write_handle = unsafe {
273            kernel32::CreateFileW(
274                pipe_name.as_ptr(),
275                winapi::GENERIC_WRITE,
276                0,
277                null_mut(),
278                winapi::OPEN_EXISTING,
279                0,
280                null_mut(),
281            )
282        };
283        let mut output_write_child = null_mut();
284        if unsafe {
285            kernel32::DuplicateHandle(
286                kernel32::GetCurrentProcess(),
287                output_write_handle,
288                kernel32::GetCurrentProcess(),
289                &mut output_write_child as _,
290                0,
291                winapi::TRUE,
292                winapi::DUPLICATE_SAME_ACCESS,
293            )
294        } == winapi::FALSE
295        {
296
297            fatal!("DuplicateHandle : {}", errno::errno());
298        }
299
300        unsafe {
301            kernel32::CloseHandle(output_write_handle);
302        }
303
304        output_write_child
305    }
306
307    pub fn on_pipe_ready(&mut self) {
308        use winapi;
309        use kernel32;
310        use errno;
311        use std::mem::{zeroed, size_of_val};
312        use std::ptr::null_mut;
313
314        let mut bytes = 0 as winapi::DWORD;
315        if unsafe {
316            kernel32::GetOverlappedResult(
317                self.extra.pipe,
318                &mut self.extra.overlapped as *mut _,
319                &mut bytes as *mut _,
320                winapi::TRUE,
321            )
322        } == winapi::FALSE
323        {
324
325            if unsafe { kernel32::GetLastError() } == winapi::ERROR_BROKEN_PIPE {
326                unsafe { kernel32::CloseHandle(self.extra.pipe) };
327                self.extra.pipe = null_mut();
328            } else {
329                fatal!("GetOverlappedResult: {}", errno::errno());
330            }
331            return;
332        }
333        if self.extra.is_reading && bytes > 0 {
334            self.buf.extend_from_slice(
335                &self.extra.overlapped_buf[0..(bytes as usize)],
336            );
337        }
338
339        self.extra.overlapped = unsafe { zeroed() };
340        self.extra.is_reading = true;
341
342        if unsafe {
343            kernel32::ReadFile(
344                self.extra.pipe,
345                self.extra.overlapped_buf.as_mut_ptr() as usize as _,
346                size_of_val(&self.extra.overlapped_buf) as _,
347                &mut bytes as *mut _,
348                &mut self.extra.overlapped as *mut _,
349            )
350        } == winapi::FALSE
351        {
352
353            match unsafe { kernel32::GetLastError() } {
354                winapi::ERROR_IO_PENDING => {}
355                winapi::ERROR_BROKEN_PIPE => {
356                    unsafe { kernel32::CloseHandle(self.extra.pipe) };
357                    self.extra.pipe = null_mut();
358                }
359                e => {
360                    fatal!("ReadFile : {}", errno::errno());
361                }
362            }
363            return;
364        }
365
366        // Even if we read any bytes in the readfile call, we'll enter this
367        // function again later and get them at that point.
368    }
369
370    /// Returns ExitSuccess on successful process exit, ExitInterrupted if
371    /// the process was interrupted, ExitFailure if it otherwise failed.
372    pub fn finish(&mut self) -> ExitStatus {
373        use winapi;
374        use kernel32;
375
376        if !self.exist() {
377            return ExitStatus::ExitFailure;
378        }
379
380        // TODO: add error handling for all of these.
381        unsafe {
382            kernel32::WaitForSingleObject(self.extra.child, winapi::INFINITE);
383        }
384
385        let mut exit_code = 0 as winapi::DWORD;
386        unsafe { kernel32::GetExitCodeProcess(self.extra.child, &mut exit_code as _) };
387        unsafe { kernel32::CloseHandle(self.extra.child) };
388
389        self.extra.child = ::std::ptr::null_mut();
390
391        match exit_code as _ {
392            0 => ExitStatus::ExitSuccess,
393            winapi::STATUS_CONTROL_C_EXIT => ExitStatus::ExitInterrupted,
394            _ => ExitStatus::ExitFailure,
395        }
396    }
397
398    fn done(&self) -> bool {
399        self.extra.pipe.is_null()
400    }
401}
402
403#[cfg(unix)]
404impl Subprocess {
405    pub(super) fn exist(&self) -> bool {
406        true
407    }
408
409    pub(super) fn start<T>(&mut self, set: &mut SubprocessSet<T>, command: &[u8]) -> bool {
410        use libc;
411        use libc_spawn;
412        use std::mem;
413        use std::ffi;
414        use std::ptr;
415        use errno;
416
417        unsafe {
418            let mut output_pipe: [libc::c_int; 2] = mem::zeroed();
419            if libc::pipe(output_pipe.as_mut_ptr()) < 0 {
420                fatal!("pipe: {}", errno::errno());
421            }
422
423            let pipe0 = output_pipe[0];
424            let pipe1 = output_pipe[1];
425            self.extra.fd = Some(pipe0);
426            if !set.use_ppoll() {
427                // If available, we use ppoll in DoWork(); otherwise we use pselect
428                // and so must avoid overly-large FDs.
429                if pipe0 >= libc::FD_SETSIZE as _ {
430                    fatal!("pipe: {}", errno::Errno(libc::EMFILE));
431                }
432            }
433
434            set_close_on_exec(pipe0);
435
436            let mut action: libc_spawn::posix_spawn_file_actions_t = mem::zeroed();
437            if libc_spawn::posix_spawn_file_actions_init(&mut action as _) != 0 {
438                fatal!("posix_spawn_file_actions_init: {}", errno::errno());
439            }
440
441            if libc_spawn::posix_spawn_file_actions_addclose(&mut action as _, pipe0) != 0 {
442                fatal!("posix_spawn_file_actions_addclose: {}", errno::errno());
443            }
444
445            let mut attr = mem::zeroed::<libc_spawn::posix_spawnattr_t>();
446            if libc_spawn::posix_spawnattr_init(&mut attr as _) != 0 {
447                fatal!("posix_spawnattr_init: {}", errno::errno());
448            }
449
450            let mut flags = 0;
451            flags |= libc_spawn::POSIX_SPAWN_SETSIGMASK;
452
453            if libc_spawn::posix_spawnattr_setsigmask(&mut attr as _, &mut set.extra.old_mask as _) != 0 {
454                fatal!("posix_spawnattr_setsigmask: {}", errno::errno());
455            }
456            // Signals which are set to be caught in the calling process image are set to
457            // default action in the new process image, so no explicit
458            // POSIX_SPAWN_SETSIGDEF parameter is needed.
459
460            if !self.use_console {
461                // Put the child in its own process group, so ctrl-c won't reach it.
462                flags |= libc_spawn::POSIX_SPAWN_SETPGROUP;
463                // No need to posix_spawnattr_setpgroup(&attr, 0), it's the default.
464                
465                // Open /dev/null over stdin.
466                let dev_null = ffi::CString::new("/dev/null").unwrap();
467                if libc_spawn::posix_spawn_file_actions_addopen(&mut action as _, 0, dev_null.as_ptr(), libc::O_RDONLY, 0) != 0 {
468                    fatal!("posix_spawn_file_actions_addopen: {}", errno::errno());
469                }
470                if libc_spawn::posix_spawn_file_actions_adddup2(&mut action as _, pipe1, 1) != 0 {
471                    fatal!("posix_spawn_file_actions_adddup2: {}", errno::errno());
472                }
473                if libc_spawn::posix_spawn_file_actions_adddup2(&mut action as _, pipe1, 2) != 0 {
474                    fatal!("posix_spawn_file_actions_adddup2: {}", errno::errno());
475                }
476                if libc_spawn::posix_spawn_file_actions_addclose(&mut action as _, pipe1) != 0  {
477                    fatal!("posix_spawn_file_actions_addclose: {}", errno::errno());
478                }
479                // In the console case, output_pipe is still inherited by the child and
480                // closed when the subprocess finishes, which then notifies ninja.
481            }
482            if let Some(v) = libc_spawn::optional_const::posix_spawn_usevfork() {
483                flags |= v;
484            }
485
486            if libc_spawn::posix_spawnattr_setflags(&mut attr as _, flags) != 0 {
487                fatal!("posix_spawnattr_setflags: {}", errno::errno());
488            }
489
490            let spawned_args0 = ffi::CString::new("/bin/sh").unwrap();
491            let spawned_args1 = ffi::CString::new("-c").unwrap();
492            let spawned_args2 = ffi::CString::from_vec_unchecked(command.to_owned());
493            let mut spawned_args = [spawned_args0.as_ptr(), 
494                  spawned_args1.as_ptr(), spawned_args2.as_ptr(), ptr::null_mut()];
495            self.extra.pid = Some(-1);
496            if libc_spawn::posix_spawn(self.extra.pid.as_mut().unwrap() as _,
497                spawned_args0.as_ptr(), &mut action as _, &mut attr as _,
498                spawned_args.as_mut_ptr(), libc_spawn::optional_const::environ()) != 0 {
499                self.extra.pid = None;
500                fatal!("posix_spawn: {}", errno::errno());
501            }
502
503            if libc_spawn::posix_spawnattr_destroy(&mut attr as _) != 0 {
504                fatal!("posix_spawnattr_destroy: {}", errno::errno());
505            }
506
507            if libc_spawn::posix_spawn_file_actions_destroy(&mut action as _) != 0 {
508                fatal!("posix_spawn_file_actions_destroy: {}", errno::errno());
509            }
510
511            libc::close(pipe1);
512        }
513        true
514    }
515
516    pub fn on_pipe_ready(&mut self) {
517        use libc;
518        use errno;
519        use std::mem;
520
521        unsafe {
522            let fd = self.extra.fd.unwrap_or(-1);
523            let mut buf = [0u8; 4096];
524            let len = libc::read(fd, buf.as_mut_ptr() as usize as _, mem::size_of_val(&buf));
525            if len < 0 {
526                fatal!("read: {}", errno::errno());
527            } else if len > 0 {
528                self.buf.extend_from_slice(&buf[0..len as usize]);
529            } else {
530                libc::close(fd);
531                self.extra.fd = None;
532            }
533        }
534
535    }
536
537    fn done(&self) -> bool {
538        self.extra.fd.is_none()
539    }
540
541    /// Returns ExitSuccess on successful process exit, ExitInterrupted if
542    /// the process was interrupted, ExitFailure if it otherwise failed.
543    pub fn finish(&mut self) -> ExitStatus {
544        use libc;
545        use errno;
546
547        debug_assert!(self.extra.pid.is_some());
548        unsafe {
549            let mut status: libc::c_int = 0;
550            let pid = self.extra.pid.unwrap();
551            if libc::waitpid(pid, &mut status as _, 0) < 0 {
552                fatal!("waitpid({}): {}", pid, errno::errno());
553            }
554
555            self.extra.pid = None;
556            if libc::WIFEXITED(status) {
557                let exit = libc::WEXITSTATUS(status);
558                if exit == 0 {
559                    return ExitStatus::ExitSuccess;
560                }
561            } else if libc::WIFSIGNALED(status) {
562                match libc::WTERMSIG(status) {
563                libc::SIGINT | libc::SIGTERM | libc::SIGHUP => {
564                    return ExitStatus::ExitInterrupted;
565                },
566                _ => {},
567                }
568            }
569        }
570        return ExitStatus::ExitFailure;
571    }
572}
573
574
575/*
576struct Subprocess {
577  ~Subprocess();
578
579  /// Returns ExitSuccess on successful process exit, ExitInterrupted if
580  /// the process was interrupted, ExitFailure if it otherwise failed.
581  ExitStatus Finish();
582
583  bool Done() const;
584
585  const string& GetOutput() const;
586
587 private:
588  Subprocess(bool use_console);
589  bool Start(struct SubprocessSet* set, const string& command);
590  void OnPipeReady();
591
592  string buf_;
593
594#ifdef _WIN32
595
596  HANDLE child_;
597  HANDLE pipe_;
598  OVERLAPPED overlapped_;
599  char overlapped_buf_[4 << 10];
600  bool is_reading_;
601#else
602  int fd_;
603  pid_t pid_;
604#endif
605  bool use_console_;
606
607  friend struct SubprocessSet;
608};
609*/
610
611#[cfg(windows)]
612struct SubprocessSetOs {}
613
614#[cfg(windows)]
615thread_local! {
616    static IOPORT : ::std::cell::Cell<::winapi::HANDLE> =
617        ::std::cell::Cell::new(::std::ptr::null_mut());
618}
619
620#[cfg(windows)]
621unsafe extern "system" fn notify_interrupted(_: ::winapi::DWORD) -> ::winapi::BOOL {
622    unimplemented!{}
623}
624
625#[cfg(windows)]
626impl SubprocessSetOs {
627    pub fn new() -> Self {
628        use winapi;
629        use kernel32;
630        use errno;
631        use std::ptr::null_mut;
632
633        let v = SubprocessSetOs {};
634        let ioport = unsafe {
635            kernel32::CreateIoCompletionPort(winapi::INVALID_HANDLE_VALUE, null_mut(), 0, 1)
636        };
637        if ioport.is_null() {
638            fatal!("CreateIoCompletionPort: {}", errno::errno());
639        }
640        v.set_ioport(ioport);
641        if unsafe { kernel32::SetConsoleCtrlHandler(Some(notify_interrupted), winapi::TRUE) } ==
642            winapi::FALSE
643        {
644            fatal!("SetConsoleCtrlHandler: {}", errno::errno());
645        }
646        v
647    }
648
649    pub fn ioport(&self) -> ::winapi::HANDLE {
650        IOPORT.with(|p| p.get())
651    }
652
653    pub fn set_ioport(&self, ioport: ::winapi::HANDLE) {
654        IOPORT.with(|p| p.set(ioport))
655    }
656}
657
658#[cfg(unix)]
659thread_local! {
660    static INTERRUPTED : ::std::cell::Cell<::libc::c_int> =
661        ::std::cell::Cell::new(0);
662}
663
664#[cfg(unix)]
665unsafe extern "C" fn set_interrupted_flag(signum: ::libc::c_int) {
666    INTERRUPTED.with(|x| x.set(signum));
667}
668
669#[cfg(unix)]
670unsafe fn handle_pending_interruption() {
671    use libc;
672    use std::mem;
673    use errno;
674
675    let mut pending = mem::zeroed::<libc::sigset_t>();
676    libc::sigemptyset(&mut pending as _);
677    if libc::sigpending(&mut pending as _) == -1 {
678        fatal!("ninja: sigpending: {}", errno::errno());
679    }
680
681    if libc::sigismember(&mut pending as _, libc::SIGINT) != 0 {
682        INTERRUPTED.with(|x| x.set(libc::SIGINT));
683    } else if libc::sigismember(&mut pending as _, libc::SIGTERM) != 0 {
684        INTERRUPTED.with(|x| x.set(libc::SIGTERM));
685    } else if libc::sigismember(&mut pending as _, libc::SIGHUP) != 0 {
686        INTERRUPTED.with(|x| x.set(libc::SIGHUP));
687    }
688}
689
690#[cfg(unix)]
691fn is_interrupted() -> bool { 
692    return INTERRUPTED.with(|x| x.get() != 0);
693}
694
695
696#[cfg(unix)]
697struct SubprocessSetOs {
698    old_int_act: ::libc::sigaction,
699    old_term_act: ::libc::sigaction,
700    old_hup_act: ::libc::sigaction,
701    old_mask:    ::libc::sigset_t,
702}
703
704#[cfg(unix)]
705impl SubprocessSetOs {
706    pub fn new() -> Self {
707        use std::mem;
708        use libc;
709        use errno;
710
711        let mut v = unsafe { mem::zeroed::<Self>() };
712        unsafe {
713            let mut set = mem::zeroed::<libc::sigset_t>();
714            libc::sigemptyset(&mut set as _);
715            libc::sigaddset(&mut set as _, libc::SIGINT);
716            libc::sigaddset(&mut set as _, libc::SIGTERM);
717            libc::sigaddset(&mut set as _, libc::SIGHUP);
718            if libc::sigprocmask(libc::SIG_BLOCK, &mut set as _, &mut v.old_mask as _) < 0 {
719                fatal!("sigprocmask: {}", errno::errno());
720            }
721
722            let mut act = mem::zeroed::<libc::sigaction>();
723            act.sa_sigaction = set_interrupted_flag as _;
724
725            if libc::sigaction(libc::SIGINT, &mut act as _, &mut v.old_int_act) < 0
726              || libc::sigaction(libc::SIGTERM, &mut act as _, &mut v.old_term_act) < 0
727              || libc::sigaction(libc::SIGHUP, &mut act as _, &mut v.old_hup_act) < 0 {
728                fatal!("sigaction: {}", errno::errno());
729            }
730
731            if libc::sigprocmask(libc::SIG_BLOCK, &mut set as _, &mut v.old_mask as _) < 0 {
732                fatal!("sigprocmask: {}", errno::errno());
733            }      
734        }       
735
736        v
737    }
738}
739
740#[cfg(unix)]
741impl Drop for SubprocessSetOs {
742    fn drop(&mut self) {
743        use libc;
744        use errno;
745        use std::ptr;
746
747        unsafe {
748            if libc::sigaction(libc::SIGINT, &mut self.old_int_act, ptr::null_mut()) < 0
749              || libc::sigaction(libc::SIGTERM, &mut self.old_term_act, ptr::null_mut()) < 0
750              || libc::sigaction(libc::SIGHUP, &mut self.old_hup_act, ptr::null_mut()) < 0 {
751                fatal!("sigaction: {}", errno::errno());
752            }
753
754            if libc::sigprocmask(libc::SIG_SETMASK, &mut self.old_mask as _, ptr::null_mut()) < 0 {
755                fatal!("sigprocmask: {}", errno::errno());
756            }
757
758        }        
759    }
760}
761
762/// SubprocessSet runs a ppoll/pselect() loop around a set of Subprocesses.
763/// DoWork() waits for any state change in subprocesses; finished_
764/// is a queue of subprocesses as they finish.
765pub struct SubprocessSet<Data = ()> {
766    running: HashMap<usize, (Box<Subprocess>, Data)>,
767    finished: VecDeque<(Box<Subprocess>, Data)>,
768    extra: SubprocessSetOs,
769}
770
771type Iter<'a, Data> = ::std::iter::Chain<
772    ::std::collections::vec_deque::Iter<
773        'a,
774        (Box<Subprocess>,
775         Data),
776    >,
777    ::std::collections::hash_map::Values<
778        'a,
779        usize,
780        (Box<Subprocess>,
781         Data),
782    >,
783>;
784
785impl<Data> SubprocessSet<Data> {
786    pub fn new() -> Self {
787        SubprocessSet {
788            running: HashMap::new(),
789            finished: VecDeque::new(),
790            extra: SubprocessSetOs::new(),
791        }
792    }
793
794    pub fn running(&self) -> &HashMap<usize, (Box<Subprocess>, Data)> {
795        &self.running
796    }
797
798    pub fn finished(&self) -> &VecDeque<(Box<Subprocess>, Data)> {
799        &self.finished
800    }
801
802    pub fn add(
803        &mut self,
804        command: &[u8],
805        use_console: bool,
806        data: Data,
807    ) -> Option<&mut (Box<Subprocess>, Data)> {
808
809        let mut subprocess = Subprocess::new(use_console);
810        if !subprocess.start(self, command) {
811            return None;
812        }
813
814        if subprocess.exist() {
815            let key = subprocess.as_ref() as *const _ as usize;
816            self.running.insert(key, (subprocess, data));
817            return self.running.get_mut(&key);
818        } else {
819            self.finished.push_back((subprocess, data));
820            return self.finished.back_mut();
821        }
822    }
823
824    pub fn next_finished(&mut self) -> Option<(Box<Subprocess>, Data)> {
825        self.finished.pop_front()
826    }
827
828    pub fn iter<'a>(&'a self) -> Iter<'a, Data> {
829        self.finished.iter().chain(self.running.values())
830    }
831
832    pub fn clear(&mut self) {
833        self.running.clear();
834        return;
835        unimplemented!{}
836    }
837}
838
839#[cfg(windows)]
840impl<Data> SubprocessSet<Data> {
841    // return Err(()) if interrupted.
842    pub fn do_work(&mut self) -> Result<(), ()> {
843        use winapi;
844        use kernel32;
845        use errno;
846        use std::ptr::null_mut;
847
848        let mut bytes_read = 0 as winapi::DWORD;
849        let mut subproc = null_mut::<Subprocess>();
850        let mut overlapped = null_mut::<winapi::OVERLAPPED>();
851
852        if unsafe {
853            kernel32::GetQueuedCompletionStatus(
854                self.extra.ioport(),
855                &mut bytes_read as _,
856                &mut subproc as *mut _ as usize as _,
857                &mut overlapped as *mut _,
858                winapi::INFINITE,
859            )
860        } == winapi::FALSE
861        {
862            if unsafe { kernel32::GetLastError() } != winapi::ERROR_BROKEN_PIPE {
863                fatal!("GetQueuedCompletionStatus: {}", errno::errno());
864            }
865        }
866
867        let done = if let Some(subproc) = unsafe { subproc.as_mut() } {
868            subproc.on_pipe_ready();
869
870            subproc.done()
871        } else {
872            // A NULL subproc indicates that we were interrupted and is
873            // delivered by NotifyInterrupted above.
874            return Err(());
875        };
876
877        if done {
878            self.finished.extend(
879                self.running
880                    .remove(&(subproc as usize))
881                    .into_iter(),
882            );
883        }
884
885        return Ok(());
886    }
887}
888
889#[cfg(unix)]
890impl<Data> SubprocessSet<Data> {
891    
892}
893
894#[cfg(all(unix, 
895          not(any(target_env = "uclibc", target_env = "newlib")),
896          any(target_os = "linux",
897              target_os = "android",
898              target_os = "emscripten",
899              target_os = "fuchsia")))]
900impl<Data> SubprocessSet<Data> {
901    pub fn use_ppoll(&self) -> bool {
902        true
903    }
904
905    // return Err(()) if interrupted.
906    pub fn do_work(&mut self) -> Result<(), ()> {
907        use std::mem;
908        use std::ptr;
909        use libc;
910        use errno;
911
912        unsafe {
913            let mut fds = Vec::new();
914            let mut nfds = 0 as libc::nfds_t;
915
916            self.running.iter().for_each(|p| {
917                if let Some(fd) = (p.1).0.extra.fd.clone() {
918                    fds.push(libc::pollfd {
919                        fd,
920                        events: libc::POLLIN | libc::POLLPRI,
921                        revents: 0,
922                    });
923                    nfds += 1;
924                }
925            });
926            INTERRUPTED.with(|x| x.set(0));
927            let ret = libc::ppoll(fds.as_mut_ptr(), nfds, ptr::null_mut(), &mut self.extra.old_mask as _);
928            if ret == -1 {
929                let errno = errno::errno();
930                if errno.0 != libc::EINTR {
931                    fatal!("ninja: ppoll: {}", errno);
932                } else if is_interrupted() {
933                    return Err(());
934                } else {
935                    return Ok(());
936                }
937            }
938
939            handle_pending_interruption();
940
941            if is_interrupted() {
942                return Err(());
943            } 
944
945            let mut removals = Vec::new();
946
947            self.running.iter_mut().enumerate().for_each(|(n, p)| {
948                if let Some(fd) = (p.1).0.extra.fd.clone() {
949                    debug_assert!(fd == fds[n].fd);
950                    if fds[n].revents != 0 {
951                        (p.1).0.on_pipe_ready();
952                        if (p.1).0.done() {
953                            removals.push(*p.0);
954                        }
955                    }
956                }
957            });
958
959            removals.into_iter().for_each(|p| {
960                self.finished.extend(self.running.remove(&p));
961            });
962
963            if is_interrupted() {
964                return Err(());
965            } else {
966                return Ok(());
967            }
968        }
969    }
970}
971
972#[cfg(all(unix, 
973          any(target_env = "uclibc", target_env = "newlib"),
974          not(any(target_os = "linux",
975                  target_os = "android",
976                  target_os = "emscripten",
977                  target_os = "fuchsia"))))]
978impl<Data> SubprocessSet<Data> {
979    pub fn use_ppoll(&self) -> bool {
980        false
981    }
982
983
984    // return Err(()) if interrupted.
985    pub fn do_work(&mut self) -> Result<(), ()> {
986        use std::mem;
987        use libc;
988        use errno;
989
990        unsafe {
991            let mut set = mem::zeroed::<libc::fd_set>();
992            let mut nfds = 0;
993            libc::FD_ZERO(&mut set as _);
994
995            self.running.iter().for_each(|p| {
996                if let Some(fd) = (p.1).0.extra.fd.clone() {
997                    libc::FD_SET(fd, &mut set as _);
998                    nfds = std::cmp::max(nfds, fd + 1);
999                }
1000            });
1001            INTERRUPTED.with(|x| x.set(0));
1002            let ret = libc::pselect(nfds, &mut set as _, 0, 0, 0, &mut self.extra.old_mask as _);
1003            if ret == -1 {
1004                let errno = errno::errno();
1005                if errno.0 != libc::EINTR {
1006                    fatal!("ninja: pselect: {}", errno);
1007                } else if is_interrupted() {
1008                    return Err(());
1009                } else {
1010                    return Ok(());
1011                }
1012            }
1013
1014            handle_pending_interruption();
1015
1016            if is_interrupted() {
1017                return Err(());
1018            } 
1019
1020            let mut removals = Vec::new();
1021
1022            self.running.iter_mut().for_each(|p| {
1023                if let Some(fd) = (p.1).0.extra.fd.clone() {
1024                    if libc::FD_ISSET(fd, &mut set as _) {
1025                        (p.1).0.on_pipe_ready();
1026                        if (p.1).0.done() {
1027                            removals.push(*p.0);
1028                        }
1029                    }
1030                }
1031            });
1032
1033            removals.into_iter().for_each(|p| {
1034                self.finished.extend(self.running.remove(&p));
1035            });
1036
1037            if is_interrupted() {
1038                return Err(());
1039            } else {
1040                return Ok(());
1041            }
1042        }
1043    }
1044}
1045
1046
1047/*
1048struct SubprocessSet {
1049  SubprocessSet();
1050  ~SubprocessSet();
1051
1052  Subprocess* Add(const string& command, bool use_console = false);
1053  bool DoWork();
1054  Subprocess* NextFinished();
1055  void Clear();
1056
1057  vector<Subprocess*> running_;
1058  queue<Subprocess*> finished_;
1059
1060#ifdef _WIN32
1061  static BOOL WINAPI NotifyInterrupted(DWORD dwCtrlType);
1062  static HANDLE ioport_;
1063#else
1064  static void SetInterruptedFlag(int signum);
1065  static void HandlePendingInterruption();
1066  /// Store the signal number that causes the interruption.
1067  /// 0 if not interruption.
1068  static int interrupted_;
1069
1070  static bool IsInterrupted() { return interrupted_ != 0; }
1071
1072  struct sigaction old_int_act_;
1073  struct sigaction old_term_act_;
1074  struct sigaction old_hup_act_;
1075  sigset_t old_mask_;
1076#endif
1077};
1078
1079#endif // NINJA_SUBPROCESS_H_
1080
1081*/
1082
1083#[cfg(windows)]
1084mod imp {
1085    /*
1086// Copyright 2012 Google Inc. All Rights Reserved.
1087//
1088// Licensed under the Apache License, Version 2.0 (the "License");
1089// you may not use this file except in compliance with the License.
1090// You may obtain a copy of the License at
1091//
1092//     http://www.apache.org/licenses/LICENSE-2.0
1093//
1094// Unless required by applicable law or agreed to in writing, software
1095// distributed under the License is distributed on an "AS IS" BASIS,
1096// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1097// See the License for the specific language governing permissions and
1098// limitations under the License.
1099
1100#include "subprocess.h"
1101
1102#include <assert.h>
1103#include <stdio.h>
1104
1105#include <algorithm>
1106
1107#include "util.h"
1108
1109Subprocess::Subprocess(bool use_console) : child_(NULL) , overlapped_(),
1110                                           is_reading_(false),
1111                                           use_console_(use_console) {
1112}
1113
1114Subprocess::~Subprocess() {
1115  if (pipe_) {
1116    if (!CloseHandle(pipe_))
1117      Win32Fatal("CloseHandle");
1118  }
1119  // Reap child if forgotten.
1120  if (child_)
1121    Finish();
1122}
1123
1124HANDLE Subprocess::SetupPipe(HANDLE ioport) {
1125  char pipe_name[100];
1126  snprintf(pipe_name, sizeof(pipe_name),
1127           "\\\\.\\pipe\\ninja_pid%lu_sp%p", GetCurrentProcessId(), this);
1128
1129  pipe_ = ::CreateNamedPipeA(pipe_name,
1130                             PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
1131                             PIPE_TYPE_BYTE,
1132                             PIPE_UNLIMITED_INSTANCES,
1133                             0, 0, INFINITE, NULL);
1134  if (pipe_ == INVALID_HANDLE_VALUE)
1135    Win32Fatal("CreateNamedPipe");
1136
1137  if (!CreateIoCompletionPort(pipe_, ioport, (ULONG_PTR)this, 0))
1138    Win32Fatal("CreateIoCompletionPort");
1139
1140  memset(&overlapped_, 0, sizeof(overlapped_));
1141  if (!ConnectNamedPipe(pipe_, &overlapped_) &&
1142      GetLastError() != ERROR_IO_PENDING) {
1143    Win32Fatal("ConnectNamedPipe");
1144  }
1145
1146  // Get the write end of the pipe as a handle inheritable across processes.
1147  HANDLE output_write_handle = CreateFile(pipe_name, GENERIC_WRITE, 0,
1148                                          NULL, OPEN_EXISTING, 0, NULL);
1149  HANDLE output_write_child;
1150  if (!DuplicateHandle(GetCurrentProcess(), output_write_handle,
1151                       GetCurrentProcess(), &output_write_child,
1152                       0, TRUE, DUPLICATE_SAME_ACCESS)) {
1153    Win32Fatal("DuplicateHandle");
1154  }
1155  CloseHandle(output_write_handle);
1156
1157  return output_write_child;
1158}
1159
1160void Subprocess::OnPipeReady() {
1161  DWORD bytes;
1162  if (!GetOverlappedResult(pipe_, &overlapped_, &bytes, TRUE)) {
1163    if (GetLastError() == ERROR_BROKEN_PIPE) {
1164      CloseHandle(pipe_);
1165      pipe_ = NULL;
1166      return;
1167    }
1168    Win32Fatal("GetOverlappedResult");
1169  }
1170
1171  if (is_reading_ && bytes)
1172    buf_.append(overlapped_buf_, bytes);
1173
1174  memset(&overlapped_, 0, sizeof(overlapped_));
1175  is_reading_ = true;
1176  if (!::ReadFile(pipe_, overlapped_buf_, sizeof(overlapped_buf_),
1177                  &bytes, &overlapped_)) {
1178    if (GetLastError() == ERROR_BROKEN_PIPE) {
1179      CloseHandle(pipe_);
1180      pipe_ = NULL;
1181      return;
1182    }
1183    if (GetLastError() != ERROR_IO_PENDING)
1184      Win32Fatal("ReadFile");
1185  }
1186
1187  // Even if we read any bytes in the readfile call, we'll enter this
1188  // function again later and get them at that point.
1189}
1190
1191ExitStatus Subprocess::Finish() {
1192  if (!child_)
1193    return ExitFailure;
1194
1195  // TODO: add error handling for all of these.
1196  WaitForSingleObject(child_, INFINITE);
1197
1198  DWORD exit_code = 0;
1199  GetExitCodeProcess(child_, &exit_code);
1200
1201  CloseHandle(child_);
1202  child_ = NULL;
1203
1204  return exit_code == 0              ? ExitSuccess :
1205         exit_code == CONTROL_C_EXIT ? ExitInterrupted :
1206                                       ExitFailure;
1207}
1208
1209
1210HANDLE SubprocessSet::ioport_;
1211
1212SubprocessSet::SubprocessSet() {
1213  ioport_ = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
1214  if (!ioport_)
1215    Win32Fatal("CreateIoCompletionPort");
1216  if (!SetConsoleCtrlHandler(NotifyInterrupted, TRUE))
1217    Win32Fatal("SetConsoleCtrlHandler");
1218}
1219
1220SubprocessSet::~SubprocessSet() {
1221  Clear();
1222
1223  SetConsoleCtrlHandler(NotifyInterrupted, FALSE);
1224  CloseHandle(ioport_);
1225}
1226
1227BOOL WINAPI SubprocessSet::NotifyInterrupted(DWORD dwCtrlType) {
1228  if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) {
1229    if (!PostQueuedCompletionStatus(ioport_, 0, 0, NULL))
1230      Win32Fatal("PostQueuedCompletionStatus");
1231    return TRUE;
1232  }
1233
1234  return FALSE;
1235}
1236
1237Subprocess *SubprocessSet::Add(const string& command, bool use_console) {
1238  Subprocess *subprocess = new Subprocess(use_console);
1239  if (!subprocess->Start(this, command)) {
1240    delete subprocess;
1241    return 0;
1242  }
1243  if (subprocess->child_)
1244    running_.push_back(subprocess);
1245  else
1246    finished_.push(subprocess);
1247  return subprocess;
1248}
1249
1250bool SubprocessSet::DoWork() {
1251  DWORD bytes_read;
1252  Subprocess* subproc;
1253  OVERLAPPED* overlapped;
1254
1255  if (!GetQueuedCompletionStatus(ioport_, &bytes_read, (PULONG_PTR)&subproc,
1256                                 &overlapped, INFINITE)) {
1257    if (GetLastError() != ERROR_BROKEN_PIPE)
1258      Win32Fatal("GetQueuedCompletionStatus");
1259  }
1260
1261  if (!subproc) // A NULL subproc indicates that we were interrupted and is
1262                // delivered by NotifyInterrupted above.
1263    return true;
1264
1265  subproc->OnPipeReady();
1266
1267  if (subproc->Done()) {
1268    vector<Subprocess*>::iterator end =
1269        remove(running_.begin(), running_.end(), subproc);
1270    if (running_.end() != end) {
1271      finished_.push(subproc);
1272      running_.resize(end - running_.begin());
1273    }
1274  }
1275
1276  return false;
1277}
1278
1279void SubprocessSet::Clear() {
1280  for (vector<Subprocess*>::iterator i = running_.begin();
1281       i != running_.end(); ++i) {
1282    // Since the foreground process is in our process group, it will receive a
1283    // CTRL_C_EVENT or CTRL_BREAK_EVENT at the same time as us.
1284    if ((*i)->child_ && !(*i)->use_console_) {
1285      if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT,
1286                                    GetProcessId((*i)->child_))) {
1287        Win32Fatal("GenerateConsoleCtrlEvent");
1288      }
1289    }
1290  }
1291  for (vector<Subprocess*>::iterator i = running_.begin();
1292       i != running_.end(); ++i)
1293    delete *i;
1294  running_.clear();
1295}
1296
1297*/
1298}
1299
1300#[cfg(unix)]
1301mod imp {
1302    /*
1303// Copyright 2012 Google Inc. All Rights Reserved.
1304//
1305// Licensed under the Apache License, Version 2.0 (the "License");
1306// you may not use this file except in compliance with the License.
1307// You may obtain a copy of the License at
1308//
1309//     http://www.apache.org/licenses/LICENSE-2.0
1310//
1311// Unless required by applicable law or agreed to in writing, software
1312// distributed under the License is distributed on an "AS IS" BASIS,
1313// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1314// See the License for the specific language governing permissions and
1315// limitations under the License.
1316
1317#include "subprocess.h"
1318
1319#include <assert.h>
1320#include <errno.h>
1321#include <fcntl.h>
1322#include <poll.h>
1323#include <unistd.h>
1324#include <stdio.h>
1325#include <string.h>
1326#include <sys/wait.h>
1327#include <spawn.h>
1328
1329extern char** environ;
1330
1331#include "util.h"
1332
1333Subprocess::Subprocess(bool use_console) : fd_(-1), pid_(-1),
1334                                           use_console_(use_console) {
1335}
1336
1337Subprocess::~Subprocess() {
1338  if (fd_ >= 0)
1339    close(fd_);
1340  // Reap child if forgotten.
1341  if (pid_ != -1)
1342    Finish();
1343}
1344
1345bool Subprocess::Start(SubprocessSet* set, const string& command) {
1346  int output_pipe[2];
1347  if (pipe(output_pipe) < 0)
1348    Fatal("pipe: %s", strerror(errno));
1349  fd_ = output_pipe[0];
1350#if !defined(USE_PPOLL)
1351  // If available, we use ppoll in DoWork(); otherwise we use pselect
1352  // and so must avoid overly-large FDs.
1353  if (fd_ >= static_cast<int>(FD_SETSIZE))
1354    Fatal("pipe: %s", strerror(EMFILE));
1355#endif  // !USE_PPOLL
1356  SetCloseOnExec(fd_);
1357
1358  posix_spawn_file_actions_t action;
1359  if (posix_spawn_file_actions_init(&action) != 0)
1360    Fatal("posix_spawn_file_actions_init: %s", strerror(errno));
1361
1362  if (posix_spawn_file_actions_addclose(&action, output_pipe[0]) != 0)
1363    Fatal("posix_spawn_file_actions_addclose: %s", strerror(errno));
1364
1365  posix_spawnattr_t attr;
1366  if (posix_spawnattr_init(&attr) != 0)
1367    Fatal("posix_spawnattr_init: %s", strerror(errno));
1368
1369  short flags = 0;
1370
1371  flags |= POSIX_SPAWN_SETSIGMASK;
1372  if (posix_spawnattr_setsigmask(&attr, &set->old_mask_) != 0)
1373    Fatal("posix_spawnattr_setsigmask: %s", strerror(errno));
1374  // Signals which are set to be caught in the calling process image are set to
1375  // default action in the new process image, so no explicit
1376  // POSIX_SPAWN_SETSIGDEF parameter is needed.
1377
1378  if (!use_console_) {
1379    // Put the child in its own process group, so ctrl-c won't reach it.
1380    flags |= POSIX_SPAWN_SETPGROUP;
1381    // No need to posix_spawnattr_setpgroup(&attr, 0), it's the default.
1382
1383    // Open /dev/null over stdin.
1384    if (posix_spawn_file_actions_addopen(&action, 0, "/dev/null", O_RDONLY,
1385                                         0) != 0) {
1386      Fatal("posix_spawn_file_actions_addopen: %s", strerror(errno));
1387    }
1388
1389    if (posix_spawn_file_actions_adddup2(&action, output_pipe[1], 1) != 0)
1390      Fatal("posix_spawn_file_actions_adddup2: %s", strerror(errno));
1391    if (posix_spawn_file_actions_adddup2(&action, output_pipe[1], 2) != 0)
1392      Fatal("posix_spawn_file_actions_adddup2: %s", strerror(errno));
1393    if (posix_spawn_file_actions_addclose(&action, output_pipe[1]) != 0)
1394      Fatal("posix_spawn_file_actions_addclose: %s", strerror(errno));
1395    // In the console case, output_pipe is still inherited by the child and
1396    // closed when the subprocess finishes, which then notifies ninja.
1397  }
1398#ifdef POSIX_SPAWN_USEVFORK
1399  flags |= POSIX_SPAWN_USEVFORK;
1400#endif
1401
1402  if (posix_spawnattr_setflags(&attr, flags) != 0)
1403    Fatal("posix_spawnattr_setflags: %s", strerror(errno));
1404
1405  const char* spawned_args[] = { "/bin/sh", "-c", command.c_str(), NULL };
1406  if (posix_spawn(&pid_, "/bin/sh", &action, &attr,
1407                  const_cast<char**>(spawned_args), environ) != 0)
1408    Fatal("posix_spawn: %s", strerror(errno));
1409
1410  if (posix_spawnattr_destroy(&attr) != 0)
1411    Fatal("posix_spawnattr_destroy: %s", strerror(errno));
1412  if (posix_spawn_file_actions_destroy(&action) != 0)
1413    Fatal("posix_spawn_file_actions_destroy: %s", strerror(errno));
1414
1415  close(output_pipe[1]);
1416  return true;
1417}
1418
1419void Subprocess::OnPipeReady() {
1420  char buf[4 << 10];
1421  ssize_t len = read(fd_, buf, sizeof(buf));
1422  if (len > 0) {
1423    buf_.append(buf, len);
1424  } else {
1425    if (len < 0)
1426      Fatal("read: %s", strerror(errno));
1427    close(fd_);
1428    fd_ = -1;
1429  }
1430}
1431
1432ExitStatus Subprocess::Finish() {
1433  assert(pid_ != -1);
1434  int status;
1435  if (waitpid(pid_, &status, 0) < 0)
1436    Fatal("waitpid(%d): %s", pid_, strerror(errno));
1437  pid_ = -1;
1438
1439  if (WIFEXITED(status)) {
1440    int exit = WEXITSTATUS(status);
1441    if (exit == 0)
1442      return ExitSuccess;
1443  } else if (WIFSIGNALED(status)) {
1444    if (WTERMSIG(status) == SIGINT || WTERMSIG(status) == SIGTERM
1445        || WTERMSIG(status) == SIGHUP)
1446      return ExitInterrupted;
1447  }
1448  return ExitFailure;
1449}
1450
1451bool Subprocess::Done() const {
1452  return fd_ == -1;
1453}
1454
1455const string& Subprocess::GetOutput() const {
1456  return buf_;
1457}
1458
1459int SubprocessSet::interrupted_;
1460
1461void SubprocessSet::SetInterruptedFlag(int signum) {
1462  interrupted_ = signum;
1463}
1464
1465void SubprocessSet::HandlePendingInterruption() {
1466  sigset_t pending;
1467  sigemptyset(&pending);
1468  if (sigpending(&pending) == -1) {
1469    perror("ninja: sigpending");
1470    return;
1471  }
1472  if (sigismember(&pending, SIGINT))
1473    interrupted_ = SIGINT;
1474  else if (sigismember(&pending, SIGTERM))
1475    interrupted_ = SIGTERM;
1476  else if (sigismember(&pending, SIGHUP))
1477    interrupted_ = SIGHUP;
1478}
1479
1480SubprocessSet::SubprocessSet() {
1481  sigset_t set;
1482  sigemptyset(&set);
1483  sigaddset(&set, SIGINT);
1484  sigaddset(&set, SIGTERM);
1485  sigaddset(&set, SIGHUP);
1486  if (sigprocmask(SIG_BLOCK, &set, &old_mask_) < 0)
1487    Fatal("sigprocmask: %s", strerror(errno));
1488
1489  struct sigaction act;
1490  memset(&act, 0, sizeof(act));
1491  act.sa_handler = SetInterruptedFlag;
1492  if (sigaction(SIGINT, &act, &old_int_act_) < 0)
1493    Fatal("sigaction: %s", strerror(errno));
1494  if (sigaction(SIGTERM, &act, &old_term_act_) < 0)
1495    Fatal("sigaction: %s", strerror(errno));
1496  if (sigaction(SIGHUP, &act, &old_hup_act_) < 0)
1497    Fatal("sigaction: %s", strerror(errno));
1498}
1499
1500SubprocessSet::~SubprocessSet() {
1501  Clear();
1502
1503  if (sigaction(SIGINT, &old_int_act_, 0) < 0)
1504    Fatal("sigaction: %s", strerror(errno));
1505  if (sigaction(SIGTERM, &old_term_act_, 0) < 0)
1506    Fatal("sigaction: %s", strerror(errno));
1507  if (sigaction(SIGHUP, &old_hup_act_, 0) < 0)
1508    Fatal("sigaction: %s", strerror(errno));
1509  if (sigprocmask(SIG_SETMASK, &old_mask_, 0) < 0)
1510    Fatal("sigprocmask: %s", strerror(errno));
1511}
1512
1513Subprocess *SubprocessSet::Add(const string& command, bool use_console) {
1514  Subprocess *subprocess = new Subprocess(use_console);
1515  if (!subprocess->Start(this, command)) {
1516    delete subprocess;
1517    return 0;
1518  }
1519  running_.push_back(subprocess);
1520  return subprocess;
1521}
1522
1523#ifdef USE_PPOLL
1524bool SubprocessSet::DoWork() {
1525  vector<pollfd> fds;
1526  nfds_t nfds = 0;
1527
1528  for (vector<Subprocess*>::iterator i = running_.begin();
1529       i != running_.end(); ++i) {
1530    int fd = (*i)->fd_;
1531    if (fd < 0)
1532      continue;
1533    pollfd pfd = { fd, POLLIN | POLLPRI, 0 };
1534    fds.push_back(pfd);
1535    ++nfds;
1536  }
1537
1538  interrupted_ = 0;
1539  int ret = ppoll(&fds.front(), nfds, NULL, &old_mask_);
1540  if (ret == -1) {
1541    if (errno != EINTR) {
1542      perror("ninja: ppoll");
1543      return false;
1544    }
1545    return IsInterrupted();
1546  }
1547
1548  HandlePendingInterruption();
1549  if (IsInterrupted())
1550    return true;
1551
1552  nfds_t cur_nfd = 0;
1553  for (vector<Subprocess*>::iterator i = running_.begin();
1554       i != running_.end(); ) {
1555    int fd = (*i)->fd_;
1556    if (fd < 0)
1557      continue;
1558    assert(fd == fds[cur_nfd].fd);
1559    if (fds[cur_nfd++].revents) {
1560      (*i)->OnPipeReady();
1561      if ((*i)->Done()) {
1562        finished_.push(*i);
1563        i = running_.erase(i);
1564        continue;
1565      }
1566    }
1567    ++i;
1568  }
1569
1570  return IsInterrupted();
1571}
1572
1573#else  // !defined(USE_PPOLL)
1574bool SubprocessSet::DoWork() {
1575  fd_set set;
1576  int nfds = 0;
1577  FD_ZERO(&set);
1578
1579  for (vector<Subprocess*>::iterator i = running_.begin();
1580       i != running_.end(); ++i) {
1581    int fd = (*i)->fd_;
1582    if (fd >= 0) {
1583      FD_SET(fd, &set);
1584      if (nfds < fd+1)
1585        nfds = fd+1;
1586    }
1587  }
1588
1589  interrupted_ = 0;
1590  int ret = pselect(nfds, &set, 0, 0, 0, &old_mask_);
1591  if (ret == -1) {
1592    if (errno != EINTR) {
1593      perror("ninja: pselect");
1594      return false;
1595    }
1596    return IsInterrupted();
1597  }
1598
1599  HandlePendingInterruption();
1600  if (IsInterrupted())
1601    return true;
1602
1603  for (vector<Subprocess*>::iterator i = running_.begin();
1604       i != running_.end(); ) {
1605    int fd = (*i)->fd_;
1606    if (fd >= 0 && FD_ISSET(fd, &set)) {
1607      (*i)->OnPipeReady();
1608      if ((*i)->Done()) {
1609        finished_.push(*i);
1610        i = running_.erase(i);
1611        continue;
1612      }
1613    }
1614    ++i;
1615  }
1616
1617  return IsInterrupted();
1618}
1619#endif  // !defined(USE_PPOLL)
1620
1621Subprocess* SubprocessSet::NextFinished() {
1622  if (finished_.empty())
1623    return NULL;
1624  Subprocess* subproc = finished_.front();
1625  finished_.pop();
1626  return subproc;
1627}
1628
1629void SubprocessSet::Clear() {
1630  for (vector<Subprocess*>::iterator i = running_.begin();
1631       i != running_.end(); ++i)
1632    // Since the foreground process is in our process group, it will receive
1633    // the interruption signal (i.e. SIGINT or SIGTERM) at the same time as us.
1634    if (!(*i)->use_console_)
1635      kill(-(*i)->pid_, interrupted_);
1636  for (vector<Subprocess*>::iterator i = running_.begin();
1637       i != running_.end(); ++i)
1638    delete *i;
1639  running_.clear();
1640}
1641
1642*/
1643}
1644
1645/*
1646
1647// Copyright 2012 Google Inc. All Rights Reserved.
1648//
1649// Licensed under the Apache License, Version 2.0 (the "License");
1650// you may not use this file except in compliance with the License.
1651// You may obtain a copy of the License at
1652//
1653//     http://www.apache.org/licenses/LICENSE-2.0
1654//
1655// Unless required by applicable law or agreed to in writing, software
1656// distributed under the License is distributed on an "AS IS" BASIS,
1657// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1658// See the License for the specific language governing permissions and
1659// limitations under the License.
1660
1661#include "subprocess.h"
1662
1663#include "test.h"
1664
1665#ifndef _WIN32
1666// SetWithLots need setrlimit.
1667#include <stdio.h>
1668#include <sys/time.h>
1669#include <sys/resource.h>
1670#include <unistd.h>
1671#endif
1672
1673namespace {
1674
1675#ifdef _WIN32
1676const char* kSimpleCommand = "cmd /c dir \\";
1677#else
1678const char* kSimpleCommand = "ls /";
1679#endif
1680
1681struct SubprocessTest : public testing::Test {
1682  SubprocessSet subprocs_;
1683};
1684
1685}  // anonymous namespace
1686
1687// Run a command that fails and emits to stderr.
1688TEST_F(SubprocessTest, BadCommandStderr) {
1689  Subprocess* subproc = subprocs_.Add("cmd /c ninja_no_such_command");
1690  ASSERT_NE((Subprocess *) 0, subproc);
1691
1692  while (!subproc->Done()) {
1693    // Pretend we discovered that stderr was ready for writing.
1694    subprocs_.DoWork();
1695  }
1696
1697  EXPECT_EQ(ExitFailure, subproc->Finish());
1698  EXPECT_NE("", subproc->GetOutput());
1699}
1700
1701// Run a command that does not exist
1702TEST_F(SubprocessTest, NoSuchCommand) {
1703  Subprocess* subproc = subprocs_.Add("ninja_no_such_command");
1704  ASSERT_NE((Subprocess *) 0, subproc);
1705
1706  while (!subproc->Done()) {
1707    // Pretend we discovered that stderr was ready for writing.
1708    subprocs_.DoWork();
1709  }
1710
1711  EXPECT_EQ(ExitFailure, subproc->Finish());
1712  EXPECT_NE("", subproc->GetOutput());
1713#ifdef _WIN32
1714  ASSERT_EQ("CreateProcess failed: The system cannot find the file "
1715            "specified.\n", subproc->GetOutput());
1716#endif
1717}
1718
1719#ifndef _WIN32
1720
1721TEST_F(SubprocessTest, InterruptChild) {
1722  Subprocess* subproc = subprocs_.Add("kill -INT $$");
1723  ASSERT_NE((Subprocess *) 0, subproc);
1724
1725  while (!subproc->Done()) {
1726    subprocs_.DoWork();
1727  }
1728
1729  EXPECT_EQ(ExitInterrupted, subproc->Finish());
1730}
1731
1732TEST_F(SubprocessTest, InterruptParent) {
1733  Subprocess* subproc = subprocs_.Add("kill -INT $PPID ; sleep 1");
1734  ASSERT_NE((Subprocess *) 0, subproc);
1735
1736  while (!subproc->Done()) {
1737    bool interrupted = subprocs_.DoWork();
1738    if (interrupted)
1739      return;
1740  }
1741
1742  ASSERT_FALSE("We should have been interrupted");
1743}
1744
1745TEST_F(SubprocessTest, InterruptChildWithSigTerm) {
1746  Subprocess* subproc = subprocs_.Add("kill -TERM $$");
1747  ASSERT_NE((Subprocess *) 0, subproc);
1748
1749  while (!subproc->Done()) {
1750    subprocs_.DoWork();
1751  }
1752
1753  EXPECT_EQ(ExitInterrupted, subproc->Finish());
1754}
1755
1756TEST_F(SubprocessTest, InterruptParentWithSigTerm) {
1757  Subprocess* subproc = subprocs_.Add("kill -TERM $PPID ; sleep 1");
1758  ASSERT_NE((Subprocess *) 0, subproc);
1759
1760  while (!subproc->Done()) {
1761    bool interrupted = subprocs_.DoWork();
1762    if (interrupted)
1763      return;
1764  }
1765
1766  ASSERT_FALSE("We should have been interrupted");
1767}
1768
1769TEST_F(SubprocessTest, InterruptChildWithSigHup) {
1770  Subprocess* subproc = subprocs_.Add("kill -HUP $$");
1771  ASSERT_NE((Subprocess *) 0, subproc);
1772
1773  while (!subproc->Done()) {
1774    subprocs_.DoWork();
1775  }
1776
1777  EXPECT_EQ(ExitInterrupted, subproc->Finish());
1778}
1779
1780TEST_F(SubprocessTest, InterruptParentWithSigHup) {
1781  Subprocess* subproc = subprocs_.Add("kill -HUP $PPID ; sleep 1");
1782  ASSERT_NE((Subprocess *) 0, subproc);
1783
1784  while (!subproc->Done()) {
1785    bool interrupted = subprocs_.DoWork();
1786    if (interrupted)
1787      return;
1788  }
1789
1790  ASSERT_FALSE("We should have been interrupted");
1791}
1792
1793TEST_F(SubprocessTest, Console) {
1794  // Skip test if we don't have the console ourselves.
1795  if (isatty(0) && isatty(1) && isatty(2)) {
1796    Subprocess* subproc =
1797        subprocs_.Add("test -t 0 -a -t 1 -a -t 2", /*use_console=*/true);
1798    ASSERT_NE((Subprocess*)0, subproc);
1799
1800    while (!subproc->Done()) {
1801      subprocs_.DoWork();
1802    }
1803
1804    EXPECT_EQ(ExitSuccess, subproc->Finish());
1805  }
1806}
1807
1808#endif
1809
1810TEST_F(SubprocessTest, SetWithSingle) {
1811  Subprocess* subproc = subprocs_.Add(kSimpleCommand);
1812  ASSERT_NE((Subprocess *) 0, subproc);
1813
1814  while (!subproc->Done()) {
1815    subprocs_.DoWork();
1816  }
1817  ASSERT_EQ(ExitSuccess, subproc->Finish());
1818  ASSERT_NE("", subproc->GetOutput());
1819
1820  ASSERT_EQ(1u, subprocs_.finished_.size());
1821}
1822
1823TEST_F(SubprocessTest, SetWithMulti) {
1824  Subprocess* processes[3];
1825  const char* kCommands[3] = {
1826    kSimpleCommand,
1827#ifdef _WIN32
1828    "cmd /c echo hi",
1829    "cmd /c time /t",
1830#else
1831    "whoami",
1832    "pwd",
1833#endif
1834  };
1835
1836  for (int i = 0; i < 3; ++i) {
1837    processes[i] = subprocs_.Add(kCommands[i]);
1838    ASSERT_NE((Subprocess *) 0, processes[i]);
1839  }
1840
1841  ASSERT_EQ(3u, subprocs_.running_.size());
1842  for (int i = 0; i < 3; ++i) {
1843    ASSERT_FALSE(processes[i]->Done());
1844    ASSERT_EQ("", processes[i]->GetOutput());
1845  }
1846
1847  while (!processes[0]->Done() || !processes[1]->Done() ||
1848         !processes[2]->Done()) {
1849    ASSERT_GT(subprocs_.running_.size(), 0u);
1850    subprocs_.DoWork();
1851  }
1852
1853  ASSERT_EQ(0u, subprocs_.running_.size());
1854  ASSERT_EQ(3u, subprocs_.finished_.size());
1855
1856  for (int i = 0; i < 3; ++i) {
1857    ASSERT_EQ(ExitSuccess, processes[i]->Finish());
1858    ASSERT_NE("", processes[i]->GetOutput());
1859    delete processes[i];
1860  }
1861}
1862
1863#if defined(USE_PPOLL)
1864TEST_F(SubprocessTest, SetWithLots) {
1865  // Arbitrary big number; needs to be over 1024 to confirm we're no longer
1866  // hostage to pselect.
1867  const unsigned kNumProcs = 1025;
1868
1869  // Make sure [ulimit -n] isn't going to stop us from working.
1870  rlimit rlim;
1871  ASSERT_EQ(0, getrlimit(RLIMIT_NOFILE, &rlim));
1872  if (rlim.rlim_cur < kNumProcs) {
1873    printf("Raise [ulimit -n] above %u (currently %lu) to make this test go\n",
1874           kNumProcs, rlim.rlim_cur);
1875    return;
1876  }
1877
1878  vector<Subprocess*> procs;
1879  for (size_t i = 0; i < kNumProcs; ++i) {
1880    Subprocess* subproc = subprocs_.Add("/bin/echo");
1881    ASSERT_NE((Subprocess *) 0, subproc);
1882    procs.push_back(subproc);
1883  }
1884  while (!subprocs_.running_.empty())
1885    subprocs_.DoWork();
1886  for (size_t i = 0; i < procs.size(); ++i) {
1887    ASSERT_EQ(ExitSuccess, procs[i]->Finish());
1888    ASSERT_NE("", procs[i]->GetOutput());
1889  }
1890  ASSERT_EQ(kNumProcs, subprocs_.finished_.size());
1891}
1892#endif  // !__APPLE__ && !_WIN32
1893
1894// TODO: this test could work on Windows, just not sure how to simply
1895// read stdin.
1896#ifndef _WIN32
1897// Verify that a command that attempts to read stdin correctly thinks
1898// that stdin is closed.
1899TEST_F(SubprocessTest, ReadStdin) {
1900  Subprocess* subproc = subprocs_.Add("cat -");
1901  while (!subproc->Done()) {
1902    subprocs_.DoWork();
1903  }
1904  ASSERT_EQ(ExitSuccess, subproc->Finish());
1905  ASSERT_EQ(1u, subprocs_.finished_.size());
1906}
1907#endif  // _WIN32
1908
1909*/