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