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