@@ -84,3 +84,76 @@ impl<const N: usize> Drop for SaGuard<N> {
8484 ) ;
8585 }
8686}
87+
88+ #[ cfg( test) ]
89+ mod tests {
90+ use super :: * ;
91+ use nix:: sys:: signal:: { self , Signal } ;
92+ use nix:: unistd:: Pid ;
93+ use std:: sync:: atomic:: { AtomicBool , Ordering } ;
94+
95+ #[ test]
96+ #[ cfg_attr( miri, ignore) ]
97+ fn signal_is_ignored_while_guard_is_active ( ) {
98+ let _guard = SaGuard :: < 1 > :: new ( & [ Signal :: SIGUSR1 ] ) . unwrap ( ) ;
99+
100+ // Send SIGUSR1 to the process. The default action is to terminate, so if
101+ // the guard didn't set SIG_IGN this test process would die
102+ signal:: kill ( Pid :: this ( ) , Signal :: SIGUSR1 ) . unwrap ( ) ;
103+ }
104+
105+ /// After the guard is dropped, the original handler should be restored.
106+ /// Install a custom handler, create a guard,drop the guard, then send the
107+ /// signal and verify the custom handler fires
108+ #[ test]
109+ #[ cfg_attr( miri, ignore) ]
110+ fn original_handler_restored_after_drop ( ) {
111+ static HANDLER_CALLED : AtomicBool = AtomicBool :: new ( false ) ;
112+
113+ extern "C" fn custom_handler ( _: libc:: c_int ) {
114+ HANDLER_CALLED . store ( true , Ordering :: SeqCst ) ;
115+ }
116+
117+ // Install a custom handler
118+ let custom_action = SigAction :: new (
119+ SigHandler :: Handler ( custom_handler) ,
120+ SaFlags :: empty ( ) ,
121+ signal:: SigSet :: empty ( ) ,
122+ ) ;
123+ let prev = unsafe { signal:: sigaction ( Signal :: SIGUSR2 , & custom_action) . unwrap ( ) } ;
124+
125+ // Create then drop the guard (dropped when out of scope)
126+ {
127+ let _guard = SaGuard :: < 1 > :: new ( & [ Signal :: SIGUSR2 ] ) . unwrap ( ) ;
128+ signal:: kill ( Pid :: this ( ) , Signal :: SIGUSR2 ) . unwrap ( ) ;
129+ assert ! (
130+ !HANDLER_CALLED . load( Ordering :: SeqCst ) ,
131+ "custom handler should not fire while guard is active"
132+ ) ;
133+ }
134+ // Guard is dropped; custom handler should be restored
135+ HANDLER_CALLED . store ( false , Ordering :: SeqCst ) ;
136+ unsafe {
137+ libc:: raise ( Signal :: SIGUSR2 as libc:: c_int ) ;
138+ }
139+ assert ! (
140+ HANDLER_CALLED . load( Ordering :: SeqCst ) ,
141+ "custom handler should fire after guard is dropped"
142+ ) ;
143+
144+ // Restore original handler
145+ unsafe {
146+ signal:: sigaction ( Signal :: SIGUSR2 , & prev) . unwrap ( ) ;
147+ }
148+ }
149+
150+ #[ test]
151+ #[ cfg_attr( miri, ignore) ]
152+ fn multiple_signals_ignored ( ) {
153+ let _guard = SaGuard :: < 2 > :: new ( & [ Signal :: SIGUSR1 , Signal :: SIGUSR2 ] ) . unwrap ( ) ;
154+
155+ // Both signals should be safely ignored
156+ signal:: kill ( Pid :: this ( ) , Signal :: SIGUSR1 ) . unwrap ( ) ;
157+ signal:: kill ( Pid :: this ( ) , Signal :: SIGUSR2 ) . unwrap ( ) ;
158+ }
159+ }
0 commit comments