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