1
- //! A simple easy to use wrapper around Ctrl-C signal .
1
+ //! A simple easy to use wrapper around unix signals .
2
2
3
3
#![ cfg_attr( feature="nightly" , feature( static_condvar) ) ]
4
4
#![ cfg_attr( feature="nightly" , feature( static_mutex) ) ]
@@ -9,84 +9,131 @@ extern crate lazy_static;
9
9
10
10
use std:: sync:: atomic:: Ordering ;
11
11
12
+ #[ derive( Clone , Copy , PartialEq , Eq , Debug ) ]
13
+ pub enum Signal {
14
+ Hup ,
15
+ Int ,
16
+ Quit ,
17
+ Ill ,
18
+ Abrt ,
19
+ Fpe ,
20
+ Kill ,
21
+ Segv ,
22
+ Pipe ,
23
+ Alrm ,
24
+ Term ,
25
+ }
26
+
12
27
#[ cfg( feature="nightly" ) ]
13
28
mod features {
14
- use std:: sync:: atomic:: { AtomicBool , ATOMIC_BOOL_INIT } ;
29
+ use std:: sync:: atomic:: { AtomicUsize , ATOMIC_USIZE_INIT } ;
15
30
use std:: sync:: { StaticCondvar , CONDVAR_INIT , StaticMutex , MUTEX_INIT } ;
16
31
pub static CVAR : StaticCondvar = CONDVAR_INIT ;
17
32
pub static MUTEX : StaticMutex = MUTEX_INIT ;
18
- pub static DONE : AtomicBool = ATOMIC_BOOL_INIT ;
33
+ pub static MASK : AtomicUsize = ATOMIC_USIZE_INIT ;
19
34
}
20
35
#[ cfg( not( feature="nightly" ) ) ]
21
36
mod features {
22
- use std:: sync:: atomic:: { AtomicBool , ATOMIC_BOOL_INIT } ;
37
+ use std:: sync:: atomic:: { AtomicUsize , ATOMIC_USIZE_INIT } ;
23
38
use std:: sync:: { Condvar , Mutex } ;
24
39
lazy_static ! {
25
40
pub static ref CVAR : Condvar = Condvar :: new( ) ;
26
41
pub static ref MUTEX : Mutex <bool > = Mutex :: new( false ) ;
27
42
}
28
- pub static DONE : AtomicBool = ATOMIC_BOOL_INIT ;
43
+ pub static MASK : AtomicUsize = ATOMIC_USIZE_INIT ;
29
44
}
30
45
use self :: features:: * ;
31
46
32
47
#[ cfg( unix) ]
33
48
mod platform {
34
49
extern crate libc;
35
- use self :: libc:: c_int;
36
- use self :: libc:: types:: os:: common:: posix01:: sighandler_t;
37
- use self :: libc:: consts:: os:: posix88:: SIGINT ;
38
- use self :: libc:: funcs:: posix01:: signal:: signal;
50
+ use self :: libc:: { c_int, signal, sighandler_t} ;
51
+ use self :: libc:: { SIGHUP , SIGINT , SIGQUIT , SIGILL , SIGABRT , SIGFPE , SIGKILL , SIGSEGV , SIGPIPE , SIGALRM , SIGTERM } ;
39
52
use std:: sync:: atomic:: Ordering ;
53
+ use super :: Signal ;
40
54
41
55
#[ repr( C ) ]
42
- pub fn handler ( _: c_int ) {
43
- super :: features:: DONE . store ( true , Ordering :: Relaxed ) ;
44
- super :: features:: CVAR . notify_all ( ) ;
45
- }
46
- #[ inline]
47
- pub unsafe fn set_os_handler ( handler : fn ( c_int ) ) {
48
- signal ( SIGINT , :: std:: mem:: transmute :: < _ , sighandler_t > ( handler) ) ;
49
- }
50
- }
51
- #[ cfg( windows) ]
52
- mod platform {
53
- extern crate winapi;
54
- extern crate kernel32;
55
- use self :: kernel32:: SetConsoleCtrlHandler ;
56
- use self :: winapi:: { BOOL , DWORD , TRUE } ;
57
- use std:: sync:: atomic:: Ordering ;
56
+ pub fn handler ( sig : c_int ) {
57
+ let mask = match sig {
58
+ SIGHUP => 1 ,
59
+ SIGINT => 2 ,
60
+ SIGQUIT => 4 ,
61
+ SIGILL => 8 ,
62
+ SIGABRT => 16 ,
63
+ SIGFPE => 32 ,
64
+ SIGKILL => 64 ,
65
+ SIGSEGV => 128 ,
66
+ SIGPIPE => 256 ,
67
+ SIGALRM => 512 ,
68
+ SIGTERM => 1024 ,
69
+ _ => return ,
70
+ } ;
58
71
59
- pub unsafe extern "system" fn handler ( _: DWORD ) -> BOOL {
60
- super :: features:: DONE . store ( true , Ordering :: Relaxed ) ;
72
+ loop {
73
+ let prev_mask = super :: features:: MASK . load ( Ordering :: Relaxed ) ;
74
+ let new_mask = prev_mask | mask;
75
+ if super :: features:: MASK . compare_and_swap ( prev_mask, new_mask, Ordering :: Relaxed ) == new_mask {
76
+ break
77
+ }
78
+ }
61
79
super :: features:: CVAR . notify_all ( ) ;
62
- TRUE
63
80
}
64
81
#[ inline]
65
- pub unsafe fn set_os_handler ( handler : unsafe extern "system" fn ( DWORD ) -> BOOL ) {
66
- SetConsoleCtrlHandler ( Some ( handler) , TRUE ) ;
82
+ pub unsafe fn set_os_handler ( sig : Signal ) {
83
+ let os_sig = match sig {
84
+ Signal :: Hup => SIGHUP ,
85
+ Signal :: Int => SIGINT ,
86
+ Signal :: Quit => SIGQUIT ,
87
+ Signal :: Ill => SIGILL ,
88
+ Signal :: Abrt => SIGABRT ,
89
+ Signal :: Fpe => SIGFPE ,
90
+ Signal :: Kill => SIGKILL ,
91
+ Signal :: Segv => SIGSEGV ,
92
+ Signal :: Pipe => SIGPIPE ,
93
+ Signal :: Alrm => SIGALRM ,
94
+ Signal :: Term => SIGTERM ,
95
+ } ;
96
+
97
+ signal ( os_sig, :: std:: mem:: transmute :: < _ , sighandler_t > ( handler) ) ;
67
98
}
68
99
}
100
+
69
101
use self :: platform:: * ;
70
102
71
- pub struct CtrlC ;
72
- impl CtrlC {
73
- /// Sets up the signal handler for Ctrl-C
103
+ pub struct Signals ;
104
+ impl Signals {
105
+ /// Sets up some signals handler
74
106
/// # Example
75
107
/// ```
76
- /// use ctrlc::CtrlC ;
77
- /// CtrlC ::set_handler(| | println!("Hello world!" ));
108
+ /// use simple_signal::{Signals, Signal} ;
109
+ /// Signals ::set_handler(&[Signal::Int, Signal::Term], |signals | println!("Caught: {:?}", signals ));
78
110
/// ```
79
- pub fn set_handler < F : Fn ( ) -> ( ) + ' static + Send > ( user_handler : F ) -> ( ) {
80
- unsafe {
81
- set_os_handler ( handler ) ;
111
+ pub fn set_handler < F > ( signals : & [ Signal ] , user_handler : F ) where F : Fn ( & [ Signal ] ) + ' static + Send {
112
+ for & signal in signals . iter ( ) {
113
+ unsafe { set_os_handler ( signal ) }
82
114
}
83
115
:: std:: thread:: spawn ( move || {
116
+ let mut signals = Vec :: new ( ) ;
84
117
loop {
85
- if !DONE . load ( Ordering :: Relaxed ) {
118
+ let mask = MASK . load ( Ordering :: Relaxed ) ;
119
+ if mask == 0 {
86
120
let _ = CVAR . wait ( MUTEX . lock ( ) . unwrap ( ) ) ;
87
- DONE . store ( false , Ordering :: Relaxed ) ;
121
+ continue
88
122
}
89
- user_handler ( ) ;
123
+ signals. clear ( ) ;
124
+ if mask & 1 != 0 { signals. push ( Signal :: Hup ) }
125
+ if mask & 2 != 0 { signals. push ( Signal :: Int ) }
126
+ if mask & 4 != 0 { signals. push ( Signal :: Quit ) }
127
+ if mask & 8 != 0 { signals. push ( Signal :: Ill ) }
128
+ if mask & 16 != 0 { signals. push ( Signal :: Abrt ) }
129
+ if mask & 32 != 0 { signals. push ( Signal :: Fpe ) }
130
+ if mask & 64 != 0 { signals. push ( Signal :: Kill ) }
131
+ if mask & 128 != 0 { signals. push ( Signal :: Segv ) }
132
+ if mask & 256 != 0 { signals. push ( Signal :: Pipe ) }
133
+ if mask & 512 != 0 { signals. push ( Signal :: Alrm ) }
134
+ if mask & 1024 != 0 { signals. push ( Signal :: Term ) }
135
+ MASK . store ( 0 , Ordering :: Relaxed ) ;
136
+ user_handler ( & signals) ;
90
137
}
91
138
} ) ;
92
139
}
0 commit comments