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