• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use libc::{
6     c_int, pthread_kill, pthread_sigmask, pthread_t, sigaction, sigaddset, sigemptyset, siginfo_t,
7     sigismember, sigpending, sigset_t, sigtimedwait, sigwait, timespec, waitpid, EAGAIN, EINTR,
8     EINVAL, SA_RESTART, SIG_BLOCK, SIG_DFL, SIG_UNBLOCK, WNOHANG,
9 };
10 
11 use std::cmp::Ordering;
12 use std::convert::TryFrom;
13 use std::fmt::{self, Display};
14 use std::io;
15 use std::mem;
16 use std::os::unix::thread::JoinHandleExt;
17 use std::process::Child;
18 use std::ptr::{null, null_mut};
19 use std::result;
20 use std::thread::JoinHandle;
21 use std::time::{Duration, Instant};
22 
23 use crate::{duration_to_timespec, errno, errno_result, getsid, Pid, Result};
24 use std::ops::{Deref, DerefMut};
25 
26 const POLL_RATE: Duration = Duration::from_millis(50);
27 const DEFAULT_KILL_TIMEOUT: Duration = Duration::from_secs(5);
28 
29 #[derive(Debug)]
30 pub enum Error {
31     /// Couldn't create a sigset.
32     CreateSigset(errno::Error),
33     /// The wrapped signal has already been blocked.
34     SignalAlreadyBlocked(c_int),
35     /// Failed to check if the requested signal is in the blocked set already.
36     CompareBlockedSignals(errno::Error),
37     /// The signal could not be blocked.
38     BlockSignal(errno::Error),
39     /// The signal mask could not be retrieved.
40     RetrieveSignalMask(i32),
41     /// The signal could not be unblocked.
42     UnblockSignal(errno::Error),
43     /// Failed to wait for given signal.
44     ClearWaitPending(errno::Error),
45     /// Failed to get pending signals.
46     ClearGetPending(errno::Error),
47     /// Failed to check if given signal is in the set of pending signals.
48     ClearCheckPending(errno::Error),
49     /// Failed to send signal to pid.
50     Kill(errno::Error),
51     /// Failed to get session id.
52     GetSid(errno::Error),
53     /// Failed to wait for signal.
54     WaitForSignal(errno::Error),
55     /// Failed to wait for pid.
56     WaitPid(errno::Error),
57     /// Timeout reached.
58     TimedOut,
59     /// Failed to convert signum to Signal.
60     UnrecognizedSignum(i32),
61     /// Converted signum greater than SIGRTMAX.
62     RtSignumGreaterThanMax(Signal),
63 }
64 
65 impl Display for Error {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result66     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
67         use self::Error::*;
68 
69         match self {
70             CreateSigset(e) => write!(f, "couldn't create a sigset: {}", e),
71             SignalAlreadyBlocked(num) => write!(f, "signal {} already blocked", num),
72             CompareBlockedSignals(e) => write!(
73                 f,
74                 "failed to check whether requested signal is in the blocked set: {}",
75                 e,
76             ),
77             BlockSignal(e) => write!(f, "signal could not be blocked: {}", e),
78             RetrieveSignalMask(errno) => write!(
79                 f,
80                 "failed to retrieve signal mask: {}",
81                 io::Error::from_raw_os_error(*errno),
82             ),
83             UnblockSignal(e) => write!(f, "signal could not be unblocked: {}", e),
84             ClearWaitPending(e) => write!(f, "failed to wait for given signal: {}", e),
85             ClearGetPending(e) => write!(f, "failed to get pending signals: {}", e),
86             ClearCheckPending(e) => write!(
87                 f,
88                 "failed to check whether given signal is in the pending set: {}",
89                 e,
90             ),
91             Kill(e) => write!(f, "failed to send signal: {}", e),
92             GetSid(e) => write!(f, "failed to get session id: {}", e),
93             WaitForSignal(e) => write!(f, "failed to wait for signal: {}", e),
94             WaitPid(e) => write!(f, "failed to wait for process: {}", e),
95             TimedOut => write!(f, "timeout reached."),
96             UnrecognizedSignum(signum) => write!(f, "unrecoginized signal number: {}", signum),
97             RtSignumGreaterThanMax(signal) => {
98                 write!(f, "got RT signal greater than max: {:?}", signal)
99             }
100         }
101     }
102 }
103 
104 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
105 #[repr(i32)]
106 pub enum Signal {
107     Abort = libc::SIGABRT,
108     Alarm = libc::SIGALRM,
109     Bus = libc::SIGBUS,
110     Child = libc::SIGCHLD,
111     Continue = libc::SIGCONT,
112     ExceededFileSize = libc::SIGXFSZ,
113     FloatingPointException = libc::SIGFPE,
114     HangUp = libc::SIGHUP,
115     IllegalInstruction = libc::SIGILL,
116     Interrupt = libc::SIGINT,
117     Io = libc::SIGIO,
118     Kill = libc::SIGKILL,
119     Pipe = libc::SIGPIPE,
120     Power = libc::SIGPWR,
121     Profile = libc::SIGPROF,
122     Quit = libc::SIGQUIT,
123     SegmentationViolation = libc::SIGSEGV,
124     StackFault = libc::SIGSTKFLT,
125     Stop = libc::SIGSTOP,
126     Sys = libc::SIGSYS,
127     Trap = libc::SIGTRAP,
128     Terminate = libc::SIGTERM,
129     TtyIn = libc::SIGTTIN,
130     TtyOut = libc::SIGTTOU,
131     TtyStop = libc::SIGTSTP,
132     Urgent = libc::SIGURG,
133     User1 = libc::SIGUSR1,
134     User2 = libc::SIGUSR2,
135     VtAlarm = libc::SIGVTALRM,
136     Winch = libc::SIGWINCH,
137     Xcpu = libc::SIGXCPU,
138     // Rt signal numbers are be adjusted in the conversion to integer.
139     Rt0 = libc::SIGSYS + 1,
140     Rt1,
141     Rt2,
142     Rt3,
143     Rt4,
144     Rt5,
145     Rt6,
146     Rt7,
147     // Only 8 are guaranteed by POSIX, Linux has 32, but only 29 or 30 are usable.
148     Rt8,
149     Rt9,
150     Rt10,
151     Rt11,
152     Rt12,
153     Rt13,
154     Rt14,
155     Rt15,
156     Rt16,
157     Rt17,
158     Rt18,
159     Rt19,
160     Rt20,
161     Rt21,
162     Rt22,
163     Rt23,
164     Rt24,
165     Rt25,
166     Rt26,
167     Rt27,
168     Rt28,
169     Rt29,
170     Rt30,
171     Rt31,
172 }
173 
174 impl From<Signal> for c_int {
from(signal: Signal) -> c_int175     fn from(signal: Signal) -> c_int {
176         let num = signal as libc::c_int;
177         if num >= Signal::Rt0 as libc::c_int {
178             return num - (Signal::Rt0 as libc::c_int) + SIGRTMIN();
179         }
180         num
181     }
182 }
183 
184 impl TryFrom<c_int> for Signal {
185     type Error = Error;
186 
try_from(value: c_int) -> result::Result<Self, Self::Error>187     fn try_from(value: c_int) -> result::Result<Self, Self::Error> {
188         use Signal::*;
189 
190         Ok(match value {
191             libc::SIGABRT => Abort,
192             libc::SIGALRM => Alarm,
193             libc::SIGBUS => Bus,
194             libc::SIGCHLD => Child,
195             libc::SIGCONT => Continue,
196             libc::SIGXFSZ => ExceededFileSize,
197             libc::SIGFPE => FloatingPointException,
198             libc::SIGHUP => HangUp,
199             libc::SIGILL => IllegalInstruction,
200             libc::SIGINT => Interrupt,
201             libc::SIGIO => Io,
202             libc::SIGKILL => Kill,
203             libc::SIGPIPE => Pipe,
204             libc::SIGPWR => Power,
205             libc::SIGPROF => Profile,
206             libc::SIGQUIT => Quit,
207             libc::SIGSEGV => SegmentationViolation,
208             libc::SIGSTKFLT => StackFault,
209             libc::SIGSTOP => Stop,
210             libc::SIGSYS => Sys,
211             libc::SIGTRAP => Trap,
212             libc::SIGTERM => Terminate,
213             libc::SIGTTIN => TtyIn,
214             libc::SIGTTOU => TtyOut,
215             libc::SIGTSTP => TtyStop,
216             libc::SIGURG => Urgent,
217             libc::SIGUSR1 => User1,
218             libc::SIGUSR2 => User2,
219             libc::SIGVTALRM => VtAlarm,
220             libc::SIGWINCH => Winch,
221             libc::SIGXCPU => Xcpu,
222             _ => {
223                 if value < SIGRTMIN() {
224                     return Err(Error::UnrecognizedSignum(value));
225                 }
226                 let signal = match value - SIGRTMIN() {
227                     0 => Rt0,
228                     1 => Rt1,
229                     2 => Rt2,
230                     3 => Rt3,
231                     4 => Rt4,
232                     5 => Rt5,
233                     6 => Rt6,
234                     7 => Rt7,
235                     8 => Rt8,
236                     9 => Rt9,
237                     10 => Rt10,
238                     11 => Rt11,
239                     12 => Rt12,
240                     13 => Rt13,
241                     14 => Rt14,
242                     15 => Rt15,
243                     16 => Rt16,
244                     17 => Rt17,
245                     18 => Rt18,
246                     19 => Rt19,
247                     20 => Rt20,
248                     21 => Rt21,
249                     22 => Rt22,
250                     23 => Rt23,
251                     24 => Rt24,
252                     25 => Rt25,
253                     26 => Rt26,
254                     27 => Rt27,
255                     28 => Rt28,
256                     29 => Rt29,
257                     30 => Rt30,
258                     31 => Rt31,
259                     _ => {
260                         return Err(Error::UnrecognizedSignum(value));
261                     }
262                 };
263                 if value > SIGRTMAX() {
264                     return Err(Error::RtSignumGreaterThanMax(signal));
265                 }
266                 signal
267             }
268         })
269     }
270 }
271 
272 pub type SignalResult<T> = result::Result<T, Error>;
273 
274 #[link(name = "c")]
275 extern "C" {
__libc_current_sigrtmin() -> c_int276     fn __libc_current_sigrtmin() -> c_int;
__libc_current_sigrtmax() -> c_int277     fn __libc_current_sigrtmax() -> c_int;
278 }
279 
280 /// Returns the minimum (inclusive) real-time signal number.
281 #[allow(non_snake_case)]
SIGRTMIN() -> c_int282 pub fn SIGRTMIN() -> c_int {
283     unsafe { __libc_current_sigrtmin() }
284 }
285 
286 /// Returns the maximum (inclusive) real-time signal number.
287 #[allow(non_snake_case)]
SIGRTMAX() -> c_int288 pub fn SIGRTMAX() -> c_int {
289     unsafe { __libc_current_sigrtmax() }
290 }
291 
valid_rt_signal_num(num: c_int) -> bool292 fn valid_rt_signal_num(num: c_int) -> bool {
293     num >= SIGRTMIN() && num <= SIGRTMAX()
294 }
295 
296 /// Registers `handler` as the signal handler of signum `num`.
297 ///
298 /// # Safety
299 ///
300 /// This is considered unsafe because the given handler will be called asynchronously, interrupting
301 /// whatever the thread was doing and therefore must only do async-signal-safe operations.
register_signal_handler( num: c_int, handler: extern "C" fn(c_int), ) -> errno::Result<()>302 pub unsafe fn register_signal_handler(
303     num: c_int,
304     handler: extern "C" fn(c_int),
305 ) -> errno::Result<()> {
306     let mut sigact: sigaction = mem::zeroed();
307     sigact.sa_flags = SA_RESTART;
308     sigact.sa_sigaction = handler as *const () as usize;
309 
310     let ret = sigaction(num, &sigact, null_mut());
311     if ret < 0 {
312         return errno_result();
313     }
314 
315     Ok(())
316 }
317 
318 /// Resets the signal handler of signum `num` back to the default.
clear_signal_handler(num: c_int) -> errno::Result<()>319 pub fn clear_signal_handler(num: c_int) -> errno::Result<()> {
320     // Safe because sigaction is owned and expected to be initialized ot zeros.
321     let mut sigact: sigaction = unsafe { mem::zeroed() };
322     sigact.sa_flags = SA_RESTART;
323     sigact.sa_sigaction = SIG_DFL;
324 
325     // Safe because sigact is owned, and this is restoring the default signal handler.
326     let ret = unsafe { sigaction(num, &sigact, null_mut()) };
327     if ret < 0 {
328         return errno_result();
329     }
330 
331     Ok(())
332 }
333 
334 /// Returns true if the signal handler for signum `num` is the default.
has_default_signal_handler(num: c_int) -> errno::Result<bool>335 pub fn has_default_signal_handler(num: c_int) -> errno::Result<bool> {
336     // Safe because sigaction is owned and expected to be initialized ot zeros.
337     let mut sigact: sigaction = unsafe { mem::zeroed() };
338 
339     // Safe because sigact is owned, and this is just querying the existing state.
340     let ret = unsafe { sigaction(num, null(), &mut sigact) };
341     if ret < 0 {
342         return errno_result();
343     }
344 
345     Ok(sigact.sa_sigaction == SIG_DFL)
346 }
347 
348 /// Registers `handler` as the signal handler for the real-time signal with signum `num`.
349 ///
350 /// The value of `num` must be within [`SIGRTMIN`, `SIGRTMAX`] range.
351 ///
352 /// # Safety
353 ///
354 /// This is considered unsafe because the given handler will be called asynchronously, interrupting
355 /// whatever the thread was doing and therefore must only do async-signal-safe operations.
register_rt_signal_handler( num: c_int, handler: extern "C" fn(c_int), ) -> errno::Result<()>356 pub unsafe fn register_rt_signal_handler(
357     num: c_int,
358     handler: extern "C" fn(c_int),
359 ) -> errno::Result<()> {
360     if !valid_rt_signal_num(num) {
361         return Err(errno::Error::new(EINVAL));
362     }
363 
364     register_signal_handler(num, handler)
365 }
366 
367 /// Creates `sigset` from an array of signal numbers.
368 ///
369 /// This is a helper function used when we want to manipulate signals.
create_sigset(signals: &[c_int]) -> errno::Result<sigset_t>370 pub fn create_sigset(signals: &[c_int]) -> errno::Result<sigset_t> {
371     // sigset will actually be initialized by sigemptyset below.
372     let mut sigset: sigset_t = unsafe { mem::zeroed() };
373 
374     // Safe - return value is checked.
375     let ret = unsafe { sigemptyset(&mut sigset) };
376     if ret < 0 {
377         return errno_result();
378     }
379 
380     for signal in signals {
381         // Safe - return value is checked.
382         let ret = unsafe { sigaddset(&mut sigset, *signal) };
383         if ret < 0 {
384             return errno_result();
385         }
386     }
387 
388     Ok(sigset)
389 }
390 
391 /// Wait for signal before continuing. The signal number of the consumed signal is returned on
392 /// success. EAGAIN means the timeout was reached.
wait_for_signal(signals: &[c_int], timeout: Option<Duration>) -> errno::Result<c_int>393 pub fn wait_for_signal(signals: &[c_int], timeout: Option<Duration>) -> errno::Result<c_int> {
394     let sigset = create_sigset(signals)?;
395 
396     match timeout {
397         Some(timeout) => {
398             let ts = duration_to_timespec(timeout);
399             // Safe - return value is checked.
400             let ret = handle_eintr_errno!(unsafe { sigtimedwait(&sigset, null_mut(), &ts) });
401             if ret < 0 {
402                 errno_result()
403             } else {
404                 Ok(ret)
405             }
406         }
407         None => {
408             let mut ret: c_int = 0;
409             let err = handle_eintr_rc!(unsafe { sigwait(&sigset, &mut ret as *mut c_int) });
410             if err != 0 {
411                 Err(errno::Error::new(err))
412             } else {
413                 Ok(ret)
414             }
415         }
416     }
417 }
418 
419 /// Retrieves the signal mask of the current thread as a vector of c_ints.
get_blocked_signals() -> SignalResult<Vec<c_int>>420 pub fn get_blocked_signals() -> SignalResult<Vec<c_int>> {
421     let mut mask = Vec::new();
422 
423     // Safe - return values are checked.
424     unsafe {
425         let mut old_sigset: sigset_t = mem::zeroed();
426         let ret = pthread_sigmask(SIG_BLOCK, null(), &mut old_sigset as *mut sigset_t);
427         if ret < 0 {
428             return Err(Error::RetrieveSignalMask(ret));
429         }
430 
431         for num in 0..=SIGRTMAX() {
432             if sigismember(&old_sigset, num) > 0 {
433                 mask.push(num);
434             }
435         }
436     }
437 
438     Ok(mask)
439 }
440 
441 /// Masks given signal.
442 ///
443 /// If signal is already blocked the call will fail with Error::SignalAlreadyBlocked
444 /// result.
block_signal(num: c_int) -> SignalResult<()>445 pub fn block_signal(num: c_int) -> SignalResult<()> {
446     let sigset = create_sigset(&[num]).map_err(Error::CreateSigset)?;
447 
448     // Safe - return values are checked.
449     unsafe {
450         let mut old_sigset: sigset_t = mem::zeroed();
451         let ret = pthread_sigmask(SIG_BLOCK, &sigset, &mut old_sigset as *mut sigset_t);
452         if ret < 0 {
453             return Err(Error::BlockSignal(errno::Error::last()));
454         }
455         let ret = sigismember(&old_sigset, num);
456         match ret.cmp(&0) {
457             Ordering::Less => {
458                 return Err(Error::CompareBlockedSignals(errno::Error::last()));
459             }
460             Ordering::Greater => {
461                 return Err(Error::SignalAlreadyBlocked(num));
462             }
463             _ => (),
464         };
465     }
466     Ok(())
467 }
468 
469 /// Unmasks given signal.
unblock_signal(num: c_int) -> SignalResult<()>470 pub fn unblock_signal(num: c_int) -> SignalResult<()> {
471     let sigset = create_sigset(&[num]).map_err(Error::CreateSigset)?;
472 
473     // Safe - return value is checked.
474     let ret = unsafe { pthread_sigmask(SIG_UNBLOCK, &sigset, null_mut()) };
475     if ret < 0 {
476         return Err(Error::UnblockSignal(errno::Error::last()));
477     }
478     Ok(())
479 }
480 
481 /// Clears pending signal.
clear_signal(num: c_int) -> SignalResult<()>482 pub fn clear_signal(num: c_int) -> SignalResult<()> {
483     let sigset = create_sigset(&[num]).map_err(Error::CreateSigset)?;
484 
485     while {
486         // This is safe as we are rigorously checking return values
487         // of libc calls.
488         unsafe {
489             let mut siginfo: siginfo_t = mem::zeroed();
490             let ts = timespec {
491                 tv_sec: 0,
492                 tv_nsec: 0,
493             };
494             // Attempt to consume one instance of pending signal. If signal
495             // is not pending, the call will fail with EAGAIN or EINTR.
496             let ret = sigtimedwait(&sigset, &mut siginfo, &ts);
497             if ret < 0 {
498                 let e = errno::Error::last();
499                 match e.errno() {
500                     EAGAIN | EINTR => {}
501                     _ => {
502                         return Err(Error::ClearWaitPending(errno::Error::last()));
503                     }
504                 }
505             }
506 
507             // This sigset will be actually filled with `sigpending` call.
508             let mut chkset: sigset_t = mem::zeroed();
509             // See if more instances of the signal are pending.
510             let ret = sigpending(&mut chkset);
511             if ret < 0 {
512                 return Err(Error::ClearGetPending(errno::Error::last()));
513             }
514 
515             let ret = sigismember(&chkset, num);
516             if ret < 0 {
517                 return Err(Error::ClearCheckPending(errno::Error::last()));
518             }
519 
520             // This is do-while loop condition.
521             ret != 0
522         }
523     } {}
524 
525     Ok(())
526 }
527 
528 /// # Safety
529 /// This is marked unsafe because it allows signals to be sent to arbitrary PIDs. Sending some
530 /// signals may lead to undefined behavior. Also, the return codes of the child processes need to be
531 /// reaped to avoid leaking zombie processes.
kill(pid: Pid, signum: c_int) -> Result<()>532 pub unsafe fn kill(pid: Pid, signum: c_int) -> Result<()> {
533     let ret = libc::kill(pid, signum);
534 
535     if ret != 0 {
536         errno_result()
537     } else {
538         Ok(())
539     }
540 }
541 
542 /// Trait for threads that can be signalled via `pthread_kill`.
543 ///
544 /// Note that this is only useful for signals between SIGRTMIN and SIGRTMAX because these are
545 /// guaranteed to not be used by the C runtime.
546 ///
547 /// This is marked unsafe because the implementation of this trait must guarantee that the returned
548 /// pthread_t is valid and has a lifetime at least that of the trait object.
549 pub unsafe trait Killable {
pthread_handle(&self) -> pthread_t550     fn pthread_handle(&self) -> pthread_t;
551 
552     /// Sends the signal `num` to this killable thread.
553     ///
554     /// The value of `num` must be within [`SIGRTMIN`, `SIGRTMAX`] range.
kill(&self, num: c_int) -> errno::Result<()>555     fn kill(&self, num: c_int) -> errno::Result<()> {
556         if !valid_rt_signal_num(num) {
557             return Err(errno::Error::new(EINVAL));
558         }
559 
560         // Safe because we ensure we are using a valid pthread handle, a valid signal number, and
561         // check the return result.
562         let ret = unsafe { pthread_kill(self.pthread_handle(), num) };
563         if ret < 0 {
564             return errno_result();
565         }
566         Ok(())
567     }
568 }
569 
570 // Safe because we fulfill our contract of returning a genuine pthread handle.
571 unsafe impl<T> Killable for JoinHandle<T> {
pthread_handle(&self) -> pthread_t572     fn pthread_handle(&self) -> pthread_t {
573         self.as_pthread_t()
574     }
575 }
576 
577 /// Treat some errno's as Ok(()).
578 macro_rules! ok_if {
579     ($result:expr, $($errno:pat)|+) => {{
580     let res = $result;
581     match res {
582         Ok(_) => Ok(()),
583         Err(err) => {
584             if matches!(err.errno(), $($errno)|+) {
585                 Ok(())
586             } else {
587                 Err(err)
588             }
589         }
590     }
591     }}
592 }
593 
594 /// Terminates and reaps a child process. If the child process is a group leader, its children will
595 /// be terminated and reaped as well. After the given timeout, the child process and any relevant
596 /// children are killed (i.e. sent SIGKILL).
kill_tree(child: &mut Child, terminate_timeout: Duration) -> SignalResult<()>597 pub fn kill_tree(child: &mut Child, terminate_timeout: Duration) -> SignalResult<()> {
598     let target = {
599         let pid = child.id() as Pid;
600         if getsid(Some(pid)).map_err(Error::GetSid)? == pid {
601             -pid
602         } else {
603             pid
604         }
605     };
606 
607     // Safe because target is a child process (or group) and behavior of SIGTERM is defined.
608     ok_if!(unsafe { kill(target, libc::SIGTERM) }, libc::ESRCH).map_err(Error::Kill)?;
609 
610     // Reap the direct child first in case it waits for its descendants, afterward reap any
611     // remaining group members.
612     let start = Instant::now();
613     let mut child_running = true;
614     loop {
615         // Wait for the direct child to exit before reaping any process group members.
616         if child_running {
617             if child
618                 .try_wait()
619                 .map_err(|e| Error::WaitPid(errno::Error::from(e)))?
620                 .is_some()
621             {
622                 child_running = false;
623                 // Skip the timeout check because waitpid(..., WNOHANG) will not block.
624                 continue;
625             }
626         } else {
627             // Safe because target is a child process (or group), WNOHANG is used, and the return
628             // value is checked.
629             let ret = unsafe { waitpid(target, null_mut(), WNOHANG) };
630             match ret {
631                 -1 => {
632                     let err = errno::Error::last();
633                     if err.errno() == libc::ECHILD {
634                         // No group members to wait on.
635                         break;
636                     }
637                     return Err(Error::WaitPid(err));
638                 }
639                 0 => {}
640                 // If a process was reaped, skip the timeout check in case there are more.
641                 _ => continue,
642             };
643         }
644 
645         // Check for a timeout.
646         let elapsed = start.elapsed();
647         if elapsed > terminate_timeout {
648             // Safe because target is a child process (or group) and behavior of SIGKILL is defined.
649             ok_if!(unsafe { kill(target, libc::SIGKILL) }, libc::ESRCH).map_err(Error::Kill)?;
650             return Err(Error::TimedOut);
651         }
652 
653         // Wait a SIGCHLD or until either the remaining time or a poll interval elapses.
654         ok_if!(
655             wait_for_signal(
656                 &[libc::SIGCHLD],
657                 Some(POLL_RATE.min(terminate_timeout - elapsed))
658             ),
659             libc::EAGAIN | libc::EINTR
660         )
661         .map_err(Error::WaitForSignal)?
662     }
663 
664     Ok(())
665 }
666 
667 /// Wraps a Child process, and calls kill_tree for its process group to clean
668 /// it up when dropped.
669 pub struct KillOnDrop {
670     process: Child,
671     timeout: Duration,
672 }
673 
674 impl KillOnDrop {
675     /// Get the timeout. See timeout_mut() for more details.
timeout(&self) -> Duration676     pub fn timeout(&self) -> Duration {
677         self.timeout
678     }
679 
680     /// Change the timeout for how long child processes are waited for before
681     /// the process group is forcibly killed.
timeout_mut(&mut self) -> &mut Duration682     pub fn timeout_mut(&mut self) -> &mut Duration {
683         &mut self.timeout
684     }
685 }
686 
687 impl From<Child> for KillOnDrop {
from(process: Child) -> Self688     fn from(process: Child) -> Self {
689         KillOnDrop {
690             process,
691             timeout: DEFAULT_KILL_TIMEOUT,
692         }
693     }
694 }
695 
696 impl AsRef<Child> for KillOnDrop {
as_ref(&self) -> &Child697     fn as_ref(&self) -> &Child {
698         &self.process
699     }
700 }
701 
702 impl AsMut<Child> for KillOnDrop {
as_mut(&mut self) -> &mut Child703     fn as_mut(&mut self) -> &mut Child {
704         &mut self.process
705     }
706 }
707 
708 impl Deref for KillOnDrop {
709     type Target = Child;
710 
deref(&self) -> &Self::Target711     fn deref(&self) -> &Self::Target {
712         &self.process
713     }
714 }
715 
716 impl DerefMut for KillOnDrop {
deref_mut(&mut self) -> &mut Self::Target717     fn deref_mut(&mut self) -> &mut Self::Target {
718         &mut self.process
719     }
720 }
721 
722 impl Drop for KillOnDrop {
drop(&mut self)723     fn drop(&mut self) {
724         if let Err(err) = kill_tree(&mut self.process, self.timeout) {
725             eprintln!("failed to kill child process group: {}", err);
726         }
727     }
728 }
729