forked from oracle/railcar
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsignals.rs
132 lines (121 loc) · 4.28 KB
/
signals.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
use errors::*;
use nix::c_int;
use nix::sys::signal::{SigAction, SigHandler, SaFlags, SigSet, Signal};
use nix::sys::signal::{sigaction, kill, raise};
pub fn pass_signals(child_pid: i32) -> Result<()> {
unsafe {
CHILD_PID = child_pid;
set_handler(SigHandler::Handler(child_handler))?;
}
Ok(())
}
// NOTE: signal handlers need to know which child to pass
// a signal to. We store the child's pid in a global variable.
// The child pid is only set once prior to setting up the
// signal handler, so it should be safe to access it from the
// signal handler.
static mut CHILD_PID: i32 = 0;
extern "C" fn child_handler(signo: c_int) {
unsafe {
let _ = kill(CHILD_PID, Signal::from_c_int(signo).unwrap());
}
}
unsafe fn set_handler(handler: SigHandler) -> Result<()> {
let a = SigAction::new(handler, SaFlags::empty(), SigSet::all());
sigaction(Signal::SIGTERM, &a).chain_err(
|| "failed to sigaction",
)?;
sigaction(Signal::SIGQUIT, &a).chain_err(
|| "failed to sigaction",
)?;
sigaction(Signal::SIGINT, &a).chain_err(
|| "failed to sigaction",
)?;
sigaction(Signal::SIGHUP, &a).chain_err(
|| "failed to sigaction",
)?;
sigaction(Signal::SIGUSR1, &a).chain_err(
|| "failed to sigaction",
)?;
sigaction(Signal::SIGUSR2, &a).chain_err(
|| "failed to sigaction",
)?;
Ok(())
}
pub fn signal_children(signal: Signal) -> Result<()> {
// don't signal this thread
let mut s = SigSet::empty();
s.add(signal);
s.thread_block()?;
kill(0, signal)?;
Ok(())
}
pub fn to_signal(signal: &str) -> Result<Signal> {
Ok(match signal {
"1" | "HUP" | "SIGHUP" => Signal::SIGHUP,
"2" | "INT" | "SIGINT" => Signal::SIGINT,
"3" | "QUIT" | "SIGQUIT" => Signal::SIGQUIT,
"4" | "ILL" | "SIGILL" => Signal::SIGILL,
"5" | "BUS" | "SIGBUS" => Signal::SIGBUS,
"6" | "ABRT" | "IOT" | "SIGABRT" | "SIGIOT" => Signal::SIGABRT,
"7" | "TRAP" | "SIGTRAP" => Signal::SIGTRAP,
"8" | "FPE" | "SIGFPE" => Signal::SIGFPE,
"9" | "KILL" | "SIGKILL" => Signal::SIGKILL,
"10" | "USR1" | "SIGUSR1" => Signal::SIGUSR1,
"11" | "SEGV" | "SIGSEGV" => Signal::SIGSEGV,
"12" | "USR2" | "SIGUSR2" => Signal::SIGUSR2,
"13" | "PIPE" | "SIGPIPE" => Signal::SIGPIPE,
"14" | "ALRM" | "SIGALRM" => Signal::SIGALRM,
"15" | "TERM" | "SIGTERM" => Signal::SIGTERM,
"16" | "STKFLT" | "SIGSTKFLT" => Signal::SIGSTKFLT,
"17" | "CHLD" | "SIGCHLD" => Signal::SIGCHLD,
"18" | "CONT" | "SIGCONT" => Signal::SIGCONT,
"19" | "STOP" | "SIGSTOP" => Signal::SIGSTOP,
"20" | "TSTP" | "SIGTSTP" => Signal::SIGTSTP,
"21" | "TTIN" | "SIGTTIN" => Signal::SIGTTIN,
"22" | "TTOU" | "SIGTTOU" => Signal::SIGTTOU,
"23" | "URG" | "SIGURG" => Signal::SIGURG,
"24" | "XCPU" | "SIGXCPU" => Signal::SIGXCPU,
"25" | "XFSZ" | "SIGXFSZ" => Signal::SIGXFSZ,
"26" | "VTALRM" | "SIGVTALRM" => Signal::SIGVTALRM,
"27" | "PROF" | "SIGPROF" => Signal::SIGPROF,
"28" | "WINCH" | "SIGWINCH" => Signal::SIGWINCH,
"29" | "IO" | "SIGIO" => Signal::SIGIO,
"30" | "PWR" | "SIGPWR" => Signal::SIGPWR,
"31" | "SYS" | "SIGSYS" => Signal::SIGSYS,
_ => bail!{"{} is not a valid signal", signal},
})
}
pub fn signal_process<T: Into<Option<Signal>>>(
pid: i32,
signal: T,
) -> Result<()> {
kill(pid, signal)?;
Ok(())
}
pub fn raise_for_parent(signal: Signal) -> Result<()> {
// reset the sigaction for the signal
if signal != Signal::SIGKILL && signal != Signal::SIGSTOP {
let a =
SigAction::new(SigHandler::SigDfl, SaFlags::empty(), SigSet::all());
unsafe {
sigaction(signal, &a).chain_err(|| "failed to sigaction")?;
}
}
// make sure the signal is unblocked
let mut s = SigSet::empty();
s.add(signal);
s.thread_unblock().chain_err(|| "failed to unblock signal")?;
// raise the signal
raise(signal).chain_err(|| {
format!("failed to raise signal {:?}", signal)
})?;
Ok(())
}
pub fn wait_for_signal() -> Result<Signal> {
let s = SigSet::all();
s.thread_block()?;
let result = s.wait()?;
s.thread_unblock()?;
Ok(result)
}