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