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::sync::Arc;
16cac7dca0Sopenharmony_ci
17cac7dca0Sopenharmony_ciuse libc::{c_int, SIGFPE, SIGILL, SIGSEGV};
18cac7dca0Sopenharmony_ci#[cfg(not(windows))]
19cac7dca0Sopenharmony_ciuse libc::{siginfo_t, SIGKILL, SIGSTOP};
20cac7dca0Sopenharmony_ci
21cac7dca0Sopenharmony_ciuse crate::sig_map::SigMap;
22cac7dca0Sopenharmony_ci
23cac7dca0Sopenharmony_ci/// These signals should not be handled at all due to POSIX settings or their
24cac7dca0Sopenharmony_ci/// specialness
25cac7dca0Sopenharmony_ci#[cfg(windows)]
26cac7dca0Sopenharmony_cipub const SIGNAL_BLOCK_LIST: &[c_int] = &[SIGILL, SIGFPE, SIGSEGV];
27cac7dca0Sopenharmony_ci
28cac7dca0Sopenharmony_ci/// These signals should not be handled at all due to POSIX settings or their
29cac7dca0Sopenharmony_ci/// specialness
30cac7dca0Sopenharmony_ci#[cfg(not(windows))]
31cac7dca0Sopenharmony_cipub const SIGNAL_BLOCK_LIST: &[c_int] = &[SIGSEGV, SIGKILL, SIGSTOP, SIGILL, SIGFPE];
32cac7dca0Sopenharmony_ci
33cac7dca0Sopenharmony_ci#[cfg(windows)]
34cac7dca0Sopenharmony_citype Action = libc::sighandler_t;
35cac7dca0Sopenharmony_ci#[cfg(not(windows))]
36cac7dca0Sopenharmony_citype Action = libc::sigaction;
37cac7dca0Sopenharmony_ci
38cac7dca0Sopenharmony_ci#[cfg(not(windows))]
39cac7dca0Sopenharmony_ciuse crate::unix::sig_handler;
40cac7dca0Sopenharmony_ci#[cfg(windows)]
41cac7dca0Sopenharmony_ciuse crate::windows::sig_handler;
42cac7dca0Sopenharmony_ci
43cac7dca0Sopenharmony_ci#[cfg(windows)]
44cac7dca0Sopenharmony_citype ActionPtr = libc::sighandler_t;
45cac7dca0Sopenharmony_ci#[cfg(not(windows))]
46cac7dca0Sopenharmony_citype ActionPtr = usize;
47cac7dca0Sopenharmony_ci
48cac7dca0Sopenharmony_ci#[allow(non_camel_case_types)]
49cac7dca0Sopenharmony_ci#[cfg(windows)]
50cac7dca0Sopenharmony_cipub(crate) struct siginfo_t;
51cac7dca0Sopenharmony_ci
52cac7dca0Sopenharmony_citype SigHandler = dyn Fn(&siginfo_t) + Send + Sync;
53cac7dca0Sopenharmony_ci
54cac7dca0Sopenharmony_ci#[derive(Clone)]
55cac7dca0Sopenharmony_cipub(crate) struct Signal {
56cac7dca0Sopenharmony_ci    pub(crate) old_act: Action,
57cac7dca0Sopenharmony_ci    pub(crate) new_act: Option<Arc<SigHandler>>,
58cac7dca0Sopenharmony_ci}
59cac7dca0Sopenharmony_ci
60cac7dca0Sopenharmony_cipub(crate) struct SigAction {
61cac7dca0Sopenharmony_ci    pub(crate) sig_num: c_int,
62cac7dca0Sopenharmony_ci    pub(crate) act: Action,
63cac7dca0Sopenharmony_ci}
64cac7dca0Sopenharmony_ci
65cac7dca0Sopenharmony_ciimpl Signal {
66cac7dca0Sopenharmony_ci    pub(crate) fn new(sig_num: c_int, new_act: Arc<SigHandler>) -> io::Result<Signal> {
67cac7dca0Sopenharmony_ci        let old_act = Self::replace_sigaction(sig_num, sig_handler as ActionPtr)?;
68cac7dca0Sopenharmony_ci
69cac7dca0Sopenharmony_ci        Ok(Signal {
70cac7dca0Sopenharmony_ci            old_act,
71cac7dca0Sopenharmony_ci            new_act: Some(new_act),
72cac7dca0Sopenharmony_ci        })
73cac7dca0Sopenharmony_ci    }
74cac7dca0Sopenharmony_ci
75cac7dca0Sopenharmony_ci    pub(super) unsafe fn register_action<F>(sig_num: c_int, handler: F) -> io::Result<()>
76cac7dca0Sopenharmony_ci    where
77cac7dca0Sopenharmony_ci        F: Fn(&siginfo_t) + Sync + Send + 'static,
78cac7dca0Sopenharmony_ci    {
79cac7dca0Sopenharmony_ci        if SIGNAL_BLOCK_LIST.contains(&sig_num) {
80cac7dca0Sopenharmony_ci            return Err(io::ErrorKind::InvalidInput.into());
81cac7dca0Sopenharmony_ci        }
82cac7dca0Sopenharmony_ci
83cac7dca0Sopenharmony_ci        let sig_map = SigMap::get_instance();
84cac7dca0Sopenharmony_ci        let act = Arc::new(handler);
85cac7dca0Sopenharmony_ci        let mut write_guard = sig_map.data.write();
86cac7dca0Sopenharmony_ci        let mut new_map = write_guard.clone();
87cac7dca0Sopenharmony_ci
88cac7dca0Sopenharmony_ci        if let Some(signal) = new_map.get_mut(&sig_num) {
89cac7dca0Sopenharmony_ci            if signal.new_act.is_some() {
90cac7dca0Sopenharmony_ci                return Err(io::ErrorKind::AlreadyExists.into());
91cac7dca0Sopenharmony_ci            } else {
92cac7dca0Sopenharmony_ci                signal.new_act = Some(act);
93cac7dca0Sopenharmony_ci            }
94cac7dca0Sopenharmony_ci        } else {
95cac7dca0Sopenharmony_ci            let old_act = SigAction::get_old_action(sig_num)?;
96cac7dca0Sopenharmony_ci            sig_map.race_old.write().store(Some(old_act));
97cac7dca0Sopenharmony_ci
98cac7dca0Sopenharmony_ci            let signal = Signal::new(sig_num, act)?;
99cac7dca0Sopenharmony_ci            new_map.insert(sig_num, signal);
100cac7dca0Sopenharmony_ci        }
101cac7dca0Sopenharmony_ci        write_guard.store(new_map);
102cac7dca0Sopenharmony_ci        Ok(())
103cac7dca0Sopenharmony_ci    }
104cac7dca0Sopenharmony_ci
105cac7dca0Sopenharmony_ci    pub(super) fn deregister_action(sig_num: c_int) -> io::Result<()> {
106cac7dca0Sopenharmony_ci        let sig_map = SigMap::get_instance();
107cac7dca0Sopenharmony_ci        let mut write_guard = sig_map.data.write();
108cac7dca0Sopenharmony_ci        let mut new_map = write_guard.clone();
109cac7dca0Sopenharmony_ci        if let Some(signal) = new_map.remove(&sig_num) {
110cac7dca0Sopenharmony_ci            #[cfg(not(windows))]
111cac7dca0Sopenharmony_ci            Self::replace_sigaction(sig_num, signal.old_act.sa_sigaction)?;
112cac7dca0Sopenharmony_ci            #[cfg(windows)]
113cac7dca0Sopenharmony_ci            Self::replace_sigaction(sig_num, signal.old_act)?;
114cac7dca0Sopenharmony_ci        }
115cac7dca0Sopenharmony_ci        write_guard.store(new_map);
116cac7dca0Sopenharmony_ci        Ok(())
117cac7dca0Sopenharmony_ci    }
118cac7dca0Sopenharmony_ci
119cac7dca0Sopenharmony_ci    pub(super) fn deregister_hook(sig_num: c_int) -> io::Result<()> {
120cac7dca0Sopenharmony_ci        let global = SigMap::get_instance();
121cac7dca0Sopenharmony_ci        let mut write_guard = global.data.write();
122cac7dca0Sopenharmony_ci        let mut signal_map = write_guard.clone();
123cac7dca0Sopenharmony_ci
124cac7dca0Sopenharmony_ci        Self::replace_sigaction(sig_num, libc::SIG_DFL)?;
125cac7dca0Sopenharmony_ci
126cac7dca0Sopenharmony_ci        signal_map.remove(&sig_num);
127cac7dca0Sopenharmony_ci        write_guard.store(signal_map);
128cac7dca0Sopenharmony_ci        Ok(())
129cac7dca0Sopenharmony_ci    }
130cac7dca0Sopenharmony_ci}
131cac7dca0Sopenharmony_ci
132cac7dca0Sopenharmony_ci#[cfg(test)]
133cac7dca0Sopenharmony_cimod test {
134cac7dca0Sopenharmony_ci    use std::sync::atomic::{AtomicUsize, Ordering};
135cac7dca0Sopenharmony_ci    use std::sync::Arc;
136cac7dca0Sopenharmony_ci
137cac7dca0Sopenharmony_ci    use crate::common::Signal;
138cac7dca0Sopenharmony_ci
139cac7dca0Sopenharmony_ci    /// UT for signal creation
140cac7dca0Sopenharmony_ci    ///
141cac7dca0Sopenharmony_ci    /// # Brief
142cac7dca0Sopenharmony_ci    /// 1. Create a new signal
143cac7dca0Sopenharmony_ci    /// 2. Check if the signal is initialized correctly
144cac7dca0Sopenharmony_ci    #[test]
145cac7dca0Sopenharmony_ci    #[cfg(target_os = "linux")]
146cac7dca0Sopenharmony_ci    fn ut_signal_new() {
147cac7dca0Sopenharmony_ci        let handler = |_info: &libc::siginfo_t| {
148cac7dca0Sopenharmony_ci            let a = 1;
149cac7dca0Sopenharmony_ci            assert_eq!(a, 1);
150cac7dca0Sopenharmony_ci        };
151cac7dca0Sopenharmony_ci        let handler = Arc::new(handler);
152cac7dca0Sopenharmony_ci        let signal = Signal::new(libc::SIGINT, handler).unwrap();
153cac7dca0Sopenharmony_ci        assert!(signal.new_act.is_some());
154cac7dca0Sopenharmony_ci
155cac7dca0Sopenharmony_ci        let signal2 = signal.clone();
156cac7dca0Sopenharmony_ci        drop(signal);
157cac7dca0Sopenharmony_ci        assert!(signal2.new_act.is_some());
158cac7dca0Sopenharmony_ci    }
159cac7dca0Sopenharmony_ci
160cac7dca0Sopenharmony_ci    /// UT for signal register and deregister
161cac7dca0Sopenharmony_ci    ///
162cac7dca0Sopenharmony_ci    /// # Brief
163cac7dca0Sopenharmony_ci    /// 1. Registers two different signals with actions that increment two
164cac7dca0Sopenharmony_ci    /// different    atomic usize.
165cac7dca0Sopenharmony_ci    /// 2. Manually raises the two signals, checks if the registered action
166cac7dca0Sopenharmony_ci    /// behave    correctly.
167cac7dca0Sopenharmony_ci    /// 3. Deregisters the action of the two signals
168cac7dca0Sopenharmony_ci    /// 4. Registers the same action for one of the signals again
169cac7dca0Sopenharmony_ci    /// 5. Manually raises the signal, checks if the registered action behave
170cac7dca0Sopenharmony_ci    ///    correctly
171cac7dca0Sopenharmony_ci    /// 6. Deregisters both signal's handler hook, checks if the return is ok.
172cac7dca0Sopenharmony_ci    #[test]
173cac7dca0Sopenharmony_ci    fn ut_signal_register() {
174cac7dca0Sopenharmony_ci        let value = Arc::new(AtomicUsize::new(0));
175cac7dca0Sopenharmony_ci        let value_cpy = value.clone();
176cac7dca0Sopenharmony_ci
177cac7dca0Sopenharmony_ci        let value2 = Arc::new(AtomicUsize::new(10));
178cac7dca0Sopenharmony_ci        let value2_cpy = value2.clone();
179cac7dca0Sopenharmony_ci        let value2_cpy2 = value2.clone();
180cac7dca0Sopenharmony_ci
181cac7dca0Sopenharmony_ci        let res = unsafe {
182cac7dca0Sopenharmony_ci            Signal::register_action(libc::SIGINT, move |_| {
183cac7dca0Sopenharmony_ci                value_cpy.fetch_add(1, Ordering::Relaxed);
184cac7dca0Sopenharmony_ci            })
185cac7dca0Sopenharmony_ci        };
186cac7dca0Sopenharmony_ci        assert!(res.is_ok());
187cac7dca0Sopenharmony_ci
188cac7dca0Sopenharmony_ci        let res = unsafe {
189cac7dca0Sopenharmony_ci            Signal::register_action(libc::SIGTERM, move |_| {
190cac7dca0Sopenharmony_ci                value2_cpy.fetch_add(10, Ordering::Relaxed);
191cac7dca0Sopenharmony_ci            })
192cac7dca0Sopenharmony_ci        };
193cac7dca0Sopenharmony_ci        assert!(res.is_ok());
194cac7dca0Sopenharmony_ci        assert_eq!(value.load(Ordering::Relaxed), 0);
195cac7dca0Sopenharmony_ci
196cac7dca0Sopenharmony_ci        unsafe { libc::raise(libc::SIGINT) };
197cac7dca0Sopenharmony_ci        assert_eq!(value.load(Ordering::Relaxed), 1);
198cac7dca0Sopenharmony_ci        assert_eq!(value2.load(Ordering::Relaxed), 10);
199cac7dca0Sopenharmony_ci
200cac7dca0Sopenharmony_ci        unsafe { libc::raise(libc::SIGTERM) };
201cac7dca0Sopenharmony_ci        assert_eq!(value.load(Ordering::Relaxed), 1);
202cac7dca0Sopenharmony_ci        assert_eq!(value2.load(Ordering::Relaxed), 20);
203cac7dca0Sopenharmony_ci
204cac7dca0Sopenharmony_ci        let res = Signal::deregister_action(libc::SIGTERM);
205cac7dca0Sopenharmony_ci        assert!(res.is_ok());
206cac7dca0Sopenharmony_ci
207cac7dca0Sopenharmony_ci        Signal::deregister_action(libc::SIGINT).unwrap();
208cac7dca0Sopenharmony_ci
209cac7dca0Sopenharmony_ci        let res = unsafe {
210cac7dca0Sopenharmony_ci            Signal::register_action(libc::SIGTERM, move |_| {
211cac7dca0Sopenharmony_ci                value2_cpy2.fetch_add(20, Ordering::Relaxed);
212cac7dca0Sopenharmony_ci            })
213cac7dca0Sopenharmony_ci        };
214cac7dca0Sopenharmony_ci        assert!(res.is_ok());
215cac7dca0Sopenharmony_ci
216cac7dca0Sopenharmony_ci        unsafe { libc::raise(libc::SIGTERM) };
217cac7dca0Sopenharmony_ci        assert_eq!(value2.load(Ordering::Relaxed), 40);
218cac7dca0Sopenharmony_ci
219cac7dca0Sopenharmony_ci        let res = Signal::deregister_hook(libc::SIGTERM);
220cac7dca0Sopenharmony_ci        assert!(res.is_ok());
221cac7dca0Sopenharmony_ci
222cac7dca0Sopenharmony_ci        let res = Signal::deregister_hook(libc::SIGINT);
223cac7dca0Sopenharmony_ci        assert!(res.is_ok());
224cac7dca0Sopenharmony_ci    }
225cac7dca0Sopenharmony_ci}
226