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