7
7
8
8
use super :: SyscallReturnCode ;
9
9
use libc:: {
10
- c_int, c_void, pthread_kill, pthread_t, sigaction, siginfo_t, EINVAL , SA_SIGINFO , SIGHUP ,
11
- SIGSYS ,
10
+ c_int, c_void, pthread_kill, pthread_t, sigaction, sigfillset, siginfo_t, sigset_t, EINVAL ,
12
11
} ;
13
12
use std:: io;
14
13
use std:: mem;
15
14
use std:: os:: unix:: thread:: JoinHandleExt ;
15
+ use std:: ptr:: null_mut;
16
16
use std:: thread:: JoinHandle ;
17
17
18
- type SiginfoHandler = extern "C" fn ( num : c_int , info : * mut siginfo_t , _unused : * mut c_void ) -> ( ) ;
19
-
20
- pub enum SignalHandler {
21
- Siginfo ( SiginfoHandler ) ,
22
- // TODO add a`SimpleHandler` when `libc` adds `sa_handler` support to `sigaction`.
23
- }
24
-
25
- /// Fills a `sigaction` structure from of the signal handler.
26
- impl Into < sigaction > for SignalHandler {
27
- fn into ( self ) -> sigaction {
28
- let mut act: sigaction = unsafe { mem:: zeroed ( ) } ;
29
- match self {
30
- SignalHandler :: Siginfo ( function) => {
31
- act. sa_flags = SA_SIGINFO ;
32
- act. sa_sigaction = function as * const ( ) as usize ;
33
- }
34
- }
35
- act
36
- }
37
- }
18
+ /// Type that represents a signal handler function.
19
+ pub type SignalHandler =
20
+ extern "C" fn ( num : c_int , info : * mut siginfo_t , _unused : * mut c_void ) -> ( ) ;
38
21
39
22
extern "C" {
40
23
fn __libc_current_sigrtmin ( ) -> c_int ;
@@ -55,36 +38,47 @@ fn SIGRTMAX() -> c_int {
55
38
56
39
/// Verifies that a signal number is valid.
57
40
///
58
- /// VCPU signals need to have values enclosed within the OS limits for realtime signals,
59
- /// and the remaining ones need to be between the minimum (SIGHUP) and maximum (SIGSYS) values.
41
+ /// VCPU signals need to have values enclosed within the OS limits for realtime signals.
60
42
///
61
43
/// Will return Ok(num) or Err(EINVAL).
62
- pub fn validate_signal_num ( num : c_int , for_vcpu : bool ) -> io:: Result < c_int > {
63
- if for_vcpu {
64
- let actual_num = num + SIGRTMIN ( ) ;
65
- if actual_num <= SIGRTMAX ( ) {
66
- return Ok ( actual_num) ;
67
- }
68
- } else if SIGHUP <= num && num <= SIGSYS {
69
- return Ok ( num) ;
44
+ pub fn validate_vcpu_signal_num ( num : c_int ) -> io:: Result < c_int > {
45
+ let actual_num = num + SIGRTMIN ( ) ;
46
+ if actual_num <= SIGRTMAX ( ) {
47
+ Ok ( actual_num)
48
+ } else {
49
+ Err ( io:: Error :: from_raw_os_error ( EINVAL ) )
70
50
}
71
- Err ( io:: Error :: from_raw_os_error ( EINVAL ) )
72
51
}
73
52
74
- /// Registers `handler` as the signal handler of signum `num`.
75
- ///
76
- /// Uses `sigaction` to register the handler.
53
+ /// Registers `handler` as the vCPU's signal handler of signum `num`.
77
54
///
78
55
/// This is considered unsafe because the given handler will be called asynchronously, interrupting
79
56
/// whatever the thread was doing and therefore must only do async-signal-safe operations.
80
- pub unsafe fn register_signal_handler (
81
- num : i32 ,
82
- handler : SignalHandler ,
83
- for_vcpu : bool ,
84
- ) -> io:: Result < ( ) > {
85
- let num = validate_signal_num ( num, for_vcpu) ?;
86
- let act: sigaction = handler. into ( ) ;
87
- SyscallReturnCode ( sigaction ( num, & act, :: std:: ptr:: null_mut ( ) ) ) . into_empty_result ( )
57
+ pub unsafe fn register_vcpu_signal_handler ( num : i32 , handler : SignalHandler ) -> io:: Result < ( ) > {
58
+ let num = validate_vcpu_signal_num ( num) ?;
59
+ // Safe, because this is a POD struct.
60
+ let mut sigact: sigaction = mem:: zeroed ( ) ;
61
+ sigact. sa_flags = libc:: SA_SIGINFO ;
62
+ sigact. sa_sigaction = handler as usize ;
63
+ SyscallReturnCode ( sigaction ( num, & sigact, null_mut ( ) ) ) . into_empty_result ( )
64
+ }
65
+
66
+ /// Registers the specified signal handler for `SIGSYS`.
67
+ pub fn register_sigsys_handler ( sigsys_handler : SignalHandler ) -> Result < ( ) , io:: Error > {
68
+ // Safe, because this is a POD struct.
69
+ let mut sigact: sigaction = unsafe { mem:: zeroed ( ) } ;
70
+ sigact. sa_flags = libc:: SA_SIGINFO ;
71
+ sigact. sa_sigaction = sigsys_handler as usize ;
72
+
73
+ // We set all the bits of sa_mask, so all signals are blocked on the current thread while the
74
+ // SIGSYS handler is executing. Safe because the parameter is valid and we check the return
75
+ // value.
76
+ if unsafe { sigfillset ( & mut sigact. sa_mask as * mut sigset_t ) } < 0 {
77
+ return Err ( io:: Error :: last_os_error ( ) ) ;
78
+ }
79
+
80
+ // Safe because the parameters are valid and we check the return value.
81
+ unsafe { SyscallReturnCode ( sigaction ( libc:: SIGSYS , & sigact, null_mut ( ) ) ) . into_empty_result ( ) }
88
82
}
89
83
90
84
/// Trait for threads that can be signalled via `pthread_kill`.
@@ -101,7 +95,7 @@ pub unsafe trait Killable {
101
95
///
102
96
/// The value of `num + SIGRTMIN` must not exceed `SIGRTMAX`.
103
97
fn kill ( & self , num : i32 ) -> io:: Result < ( ) > {
104
- let num = validate_signal_num ( num, true ) ?;
98
+ let num = validate_vcpu_signal_num ( num) ?;
105
99
106
100
// Safe because we ensure we are using a valid pthread handle, a valid signal number, and
107
101
// check the return result.
@@ -119,7 +113,6 @@ unsafe impl<T> Killable for JoinHandle<T> {
119
113
#[ cfg( test) ]
120
114
mod tests {
121
115
use super :: * ;
122
- use libc;
123
116
use std:: thread;
124
117
use std:: time:: Duration ;
125
118
@@ -135,25 +128,9 @@ mod tests {
135
128
fn test_register_signal_handler ( ) {
136
129
unsafe {
137
130
// testing bad value
138
- assert ! ( register_signal_handler(
139
- SIGRTMAX ( ) ,
140
- SignalHandler :: Siginfo ( handle_signal) ,
141
- true
142
- )
143
- . is_err( ) ) ;
144
- format ! (
145
- "{:?}" ,
146
- register_signal_handler( SIGRTMAX ( ) , SignalHandler :: Siginfo ( handle_signal) , true )
147
- ) ;
148
- assert ! (
149
- register_signal_handler( 0 , SignalHandler :: Siginfo ( handle_signal) , true ) . is_ok( )
150
- ) ;
151
- assert ! ( register_signal_handler(
152
- libc:: SIGSYS ,
153
- SignalHandler :: Siginfo ( handle_signal) ,
154
- false
155
- )
156
- . is_ok( ) ) ;
131
+ assert ! ( register_vcpu_signal_handler( SIGRTMAX ( ) , handle_signal) . is_err( ) ) ;
132
+ assert ! ( register_vcpu_signal_handler( 0 , handle_signal) . is_ok( ) ) ;
133
+ assert ! ( register_sigsys_handler( handle_signal) . is_ok( ) ) ;
157
134
}
158
135
}
159
136
@@ -168,7 +145,7 @@ mod tests {
168
145
// be brought down when the signal is received, as part of the default behaviour. Signal
169
146
// handlers are global, so we install this before starting the thread.
170
147
unsafe {
171
- register_signal_handler ( 0 , SignalHandler :: Siginfo ( handle_signal) , true )
148
+ register_vcpu_signal_handler ( 0 , handle_signal)
172
149
. expect ( "failed to register vcpu signal handler" ) ;
173
150
}
174
151
0 commit comments