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