• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2023 Huawei Device Co., Ltd.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 //     http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 #![cfg(feature = "linux")]
15 
16 use std::mem::MaybeUninit;
17 use std::os::raw::c_int;
18 use std::ptr::null_mut;
19 use std::sync::atomic::{AtomicUsize, Ordering};
20 use std::sync::{Arc, Once};
21 use std::{io, mem, thread};
22 
23 /// SDV cases for signal register
24 ///
25 /// # Brief
26 /// 1. Registers two different signals with actions that increment two different
27 ///    atomic usize.
28 /// 2. Manually raises the two signals, checks if the registered action behave
29 ///    correctly.
30 /// 3. Deregisters the action of the two signals
31 /// 4. Manually raises the two signals, the actions should not be executed, and
32 ///    the program should not be terminated
33 /// 5. Registers the same action for one of the signals again
34 /// 6. Manually raises the signal, checks if the registered action behave
35 ///    correctly
36 /// 7. Deregisters both signal's handler hook, checks if the return is ok.
37 #[test]
sdv_signal_register_succeed()38 fn sdv_signal_register_succeed() {
39     let value = Arc::new(AtomicUsize::new(0));
40     let value_cpy = value.clone();
41 
42     let value2 = Arc::new(AtomicUsize::new(10));
43     let value2_cpy = value2.clone();
44     let value2_cpy2 = value2.clone();
45 
46     let res = unsafe {
47         ylong_signal::register_signal_action(libc::SIGINT, move || {
48             value_cpy.fetch_add(1, Ordering::Relaxed);
49         })
50     };
51     assert!(res.is_ok());
52 
53     let res2 = unsafe {
54         ylong_signal::register_signal_action(libc::SIGTERM, move || {
55             value2_cpy.fetch_add(10, Ordering::Relaxed);
56         })
57     };
58     assert!(res2.is_ok());
59     assert_eq!(value.load(Ordering::Relaxed), 0);
60 
61     unsafe { libc::raise(libc::SIGINT) };
62     assert_eq!(value.load(Ordering::Relaxed), 1);
63     assert_eq!(value2.load(Ordering::Relaxed), 10);
64 
65     unsafe { libc::raise(libc::SIGTERM) };
66     assert_eq!(value.load(Ordering::Relaxed), 1);
67     assert_eq!(value2.load(Ordering::Relaxed), 20);
68 
69     ylong_signal::deregister_signal_action(libc::SIGTERM);
70     unsafe { libc::raise(libc::SIGTERM) };
71     assert_eq!(value2.load(Ordering::Relaxed), 20);
72 
73     ylong_signal::deregister_signal_action(libc::SIGINT);
74 
75     let res3 = unsafe {
76         ylong_signal::register_signal_action(libc::SIGTERM, move || {
77             value2_cpy2.fetch_add(20, Ordering::Relaxed);
78         })
79     };
80     assert!(res3.is_ok());
81     unsafe { libc::raise(libc::SIGTERM) };
82     assert_eq!(value2.load(Ordering::Relaxed), 40);
83 
84     let res4 = ylong_signal::deregister_signal_hook(libc::SIGTERM);
85     assert!(res4.is_ok());
86 
87     let res5 = ylong_signal::deregister_signal_hook(libc::SIGINT);
88     assert!(res5.is_ok());
89 }
90 
91 /// SDV cases for signal register error handling
92 ///
93 /// # Brief
94 /// 1. Registers an action for a forbidden signal
95 /// 2. Checks if the return value is InvalidInput error
96 /// 3. Registers an action for an allowed signal
97 /// 4. Checks if the return value is Ok
98 /// 5. Registers an action for the same signal again
99 /// 6. Checks if the return value is AlreadyExists error
100 /// 7. Deregisters the signal hook of the previous registered signal
101 /// 8. Checks if the return value is OK
102 /// 9. Deregisters the signal action of an unregistered signal
103 /// 10. Deregisters the signal handler of an unregistered signal
104 /// 11. Checks if the return value is Ok
105 #[test]
sdv_signal_register_failed()106 fn sdv_signal_register_failed() {
107     let res = unsafe { ylong_signal::register_signal_action(libc::SIGSEGV, move || {}) };
108     assert_eq!(res.unwrap_err().kind(), io::ErrorKind::InvalidInput);
109 
110     let res = unsafe { ylong_signal::register_signal_action(libc::SIGQUIT, move || {}) };
111     assert!(res.is_ok());
112     let res = unsafe { ylong_signal::register_signal_action(libc::SIGQUIT, move || {}) };
113     assert_eq!(res.unwrap_err().kind(), io::ErrorKind::AlreadyExists);
114 
115     let res = ylong_signal::deregister_signal_hook(libc::SIGQUIT);
116     assert!(res.is_ok());
117 
118     ylong_signal::deregister_signal_action(libc::SIG_UNBLOCK);
119     let res = ylong_signal::deregister_signal_hook(libc::SIG_UNBLOCK);
120     assert!(res.is_ok());
121 }
122 
123 /// SDV cases for signal register when there is already an existing handler
124 ///
125 /// # Brief
126 /// 1. Registers a signal handler using libc syscall
127 /// 2. Registers a signal handler using ylong_signal::register_signal_action
128 /// 3. Manually raises the signal
129 /// 4. Checks if the old handler and the new action both get executed correctly
130 /// 5. Deregisters the signal action
131 /// 6. Manually raises the signal
132 /// 7. Checks if the old handler gets executed correctly
133 /// 8. Deregister the hook.
134 #[test]
sdv_signal_register_with_old()135 fn sdv_signal_register_with_old() {
136     let mut new_act: libc::sigaction = unsafe { mem::zeroed() };
137     new_act.sa_sigaction = test_handler as usize;
138     unsafe {
139         libc::sigaction(libc::SIGCONT, &new_act, null_mut());
140     }
141 
142     let res = unsafe {
143         ylong_signal::register_signal_action(libc::SIGCONT, move || {
144             let global = Global::get_instance();
145             assert_eq!(global.value.load(Ordering::Relaxed), 1);
146             global.value.fetch_add(2, Ordering::Relaxed);
147         })
148     };
149     assert!(res.is_ok());
150     unsafe {
151         libc::raise(libc::SIGCONT);
152     }
153     let global = Global::get_instance();
154     assert_eq!(global.value.load(Ordering::Relaxed), 3);
155 
156     ylong_signal::deregister_signal_action(libc::SIGCONT);
157     unsafe {
158         libc::raise(libc::SIGCONT);
159     }
160     assert_eq!(global.value.load(Ordering::Relaxed), 4);
161     let res = ylong_signal::deregister_signal_hook(libc::SIGCONT);
162     assert!(res.is_ok());
163 
164     unsafe {
165         libc::raise(libc::SIGCONT);
166     }
167 }
168 
169 pub struct Global {
170     value: AtomicUsize,
171 }
172 
173 impl Global {
get_instance() -> &'static Global174     fn get_instance() -> &'static Global {
175         static mut GLOBAL: MaybeUninit<Global> = MaybeUninit::uninit();
176         static ONCE: Once = Once::new();
177 
178         unsafe {
179             ONCE.call_once(|| {
180                 GLOBAL = MaybeUninit::new(Global {
181                     value: AtomicUsize::new(0),
182                 });
183             });
184             &*GLOBAL.as_ptr()
185         }
186     }
187 }
188 
test_handler(_sig_num: c_int)189 extern "C" fn test_handler(_sig_num: c_int) {
190     let global = Global::get_instance();
191     global.value.fetch_add(1, Ordering::Relaxed);
192 }
193 
194 /// SDV cases for signal register in multi-thread env
195 ///
196 /// # Brief
197 /// 1. Registers a signal handler
198 /// 2. Spawns another thread to raise the signal
199 /// 3. Raises the same signal on the main thread
200 /// 4. All execution should return OK
201 #[test]
sdv_signal_register_multi()202 fn sdv_signal_register_multi() {
203     for i in 0..1000 {
204         let res = unsafe {
205             ylong_signal::register_signal_action(libc::SIGCHLD, move || {
206                 let mut data = 100;
207                 data += i;
208                 assert_eq!(data, 100 + i);
209             })
210         };
211         thread::spawn(move || {
212             unsafe { libc::raise(libc::SIGCHLD) };
213         });
214         assert!(res.is_ok());
215         unsafe {
216             libc::raise(libc::SIGCHLD);
217         }
218 
219         ylong_signal::deregister_signal_action(libc::SIGCHLD);
220         unsafe {
221             libc::raise(libc::SIGCHLD);
222         }
223         assert!(res.is_ok());
224     }
225 }
226