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_ci//! Linux wrapping of signal syscall
15cac7dca0Sopenharmony_ci
16cac7dca0Sopenharmony_ciuse std::{io, mem, ptr};
17cac7dca0Sopenharmony_ci
18cac7dca0Sopenharmony_ciuse libc::{c_int, c_void, sigaction, siginfo_t};
19cac7dca0Sopenharmony_ci
20cac7dca0Sopenharmony_ciuse crate::common::{SigAction, Signal};
21cac7dca0Sopenharmony_ciuse crate::sig_map::SigMap;
22cac7dca0Sopenharmony_ci
23cac7dca0Sopenharmony_ciimpl SigAction {
24cac7dca0Sopenharmony_ci    pub(crate) fn get_old_action(sig_num: c_int) -> io::Result<Self> {
25cac7dca0Sopenharmony_ci        let mut old_act: libc::sigaction = unsafe { mem::zeroed() };
26cac7dca0Sopenharmony_ci        unsafe {
27cac7dca0Sopenharmony_ci            if libc::sigaction(sig_num, ptr::null(), &mut old_act) != 0 {
28cac7dca0Sopenharmony_ci                return Err(io::Error::last_os_error());
29cac7dca0Sopenharmony_ci            }
30cac7dca0Sopenharmony_ci        }
31cac7dca0Sopenharmony_ci        Ok(SigAction {
32cac7dca0Sopenharmony_ci            sig_num,
33cac7dca0Sopenharmony_ci            act: old_act,
34cac7dca0Sopenharmony_ci        })
35cac7dca0Sopenharmony_ci    }
36cac7dca0Sopenharmony_ci}
37cac7dca0Sopenharmony_ci
38cac7dca0Sopenharmony_ciimpl Signal {
39cac7dca0Sopenharmony_ci    pub(crate) fn replace_sigaction(sig_num: c_int, new_action: usize) -> io::Result<sigaction> {
40cac7dca0Sopenharmony_ci        let mut handler: libc::sigaction = unsafe { mem::zeroed() };
41cac7dca0Sopenharmony_ci        let mut old_act: libc::sigaction = unsafe { mem::zeroed() };
42cac7dca0Sopenharmony_ci
43cac7dca0Sopenharmony_ci        handler.sa_sigaction = new_action;
44cac7dca0Sopenharmony_ci        handler.sa_flags = libc::SA_RESTART | libc::SA_SIGINFO;
45cac7dca0Sopenharmony_ci
46cac7dca0Sopenharmony_ci        unsafe {
47cac7dca0Sopenharmony_ci            if libc::sigaction(sig_num, &handler, &mut old_act) != 0 {
48cac7dca0Sopenharmony_ci                return Err(io::Error::last_os_error());
49cac7dca0Sopenharmony_ci            }
50cac7dca0Sopenharmony_ci        }
51cac7dca0Sopenharmony_ci
52cac7dca0Sopenharmony_ci        Ok(old_act)
53cac7dca0Sopenharmony_ci    }
54cac7dca0Sopenharmony_ci}
55cac7dca0Sopenharmony_ci
56cac7dca0Sopenharmony_cipub(crate) extern "C" fn sig_handler(sig_num: c_int, sig_info: *mut siginfo_t, data: *mut c_void) {
57cac7dca0Sopenharmony_ci    let sig_map = SigMap::get_instance();
58cac7dca0Sopenharmony_ci    let race_fallback = sig_map.race_old.read();
59cac7dca0Sopenharmony_ci    let signals = sig_map.data.read();
60cac7dca0Sopenharmony_ci
61cac7dca0Sopenharmony_ci    if let Some(signal) = signals.get(&sig_num) {
62cac7dca0Sopenharmony_ci        // sig_info should not be null, but in a sig handler we cannot panic directly,
63cac7dca0Sopenharmony_ci        // therefore we abort instead
64cac7dca0Sopenharmony_ci        if sig_info.is_null() {
65cac7dca0Sopenharmony_ci            unsafe { libc::abort() };
66cac7dca0Sopenharmony_ci        }
67cac7dca0Sopenharmony_ci
68cac7dca0Sopenharmony_ci        let info = unsafe { &*sig_info };
69cac7dca0Sopenharmony_ci        if let Some(act) = &signal.new_act {
70cac7dca0Sopenharmony_ci            act(info);
71cac7dca0Sopenharmony_ci        }
72cac7dca0Sopenharmony_ci    } else if let Some(fallback) = race_fallback.as_ref() {
73cac7dca0Sopenharmony_ci        // There could be a race condition between swapping the old handler with the new
74cac7dca0Sopenharmony_ci        // handler and storing the change back to the global during the register
75cac7dca0Sopenharmony_ci        // procedure. Because of the race condition, the old handler and the new
76cac7dca0Sopenharmony_ci        // action could both not get executed. In order to prevent this, we
77cac7dca0Sopenharmony_ci        // store the old handler into global before swapping the handler in
78cac7dca0Sopenharmony_ci        // register. And during the handler execution, if the the action
79cac7dca0Sopenharmony_ci        // of the signal cannot be found, we execute this old handler instead if the
80cac7dca0Sopenharmony_ci        // sig_num matches.
81cac7dca0Sopenharmony_ci        if fallback.sig_num == sig_num {
82cac7dca0Sopenharmony_ci            execute_act(&fallback.act, sig_num, sig_info, data);
83cac7dca0Sopenharmony_ci        }
84cac7dca0Sopenharmony_ci    }
85cac7dca0Sopenharmony_ci}
86cac7dca0Sopenharmony_ci
87cac7dca0Sopenharmony_cifn execute_act(act: &sigaction, sig_num: c_int, sig_info: *mut siginfo_t, data: *mut c_void) {
88cac7dca0Sopenharmony_ci    let handler = act.sa_sigaction;
89cac7dca0Sopenharmony_ci
90cac7dca0Sopenharmony_ci    // SIG_DFL for the default action.
91cac7dca0Sopenharmony_ci    // SIG_IGN to ignore this signal.
92cac7dca0Sopenharmony_ci    if handler == libc::SIG_DFL || handler == libc::SIG_IGN {
93cac7dca0Sopenharmony_ci        return;
94cac7dca0Sopenharmony_ci    }
95cac7dca0Sopenharmony_ci
96cac7dca0Sopenharmony_ci    // If SA_SIGINFO flag is set, then the signal handler takes three arguments, not
97cac7dca0Sopenharmony_ci    // one. In this case, sa_sigaction should be set instead of sa_handler.
98cac7dca0Sopenharmony_ci    // We transmute the handler from ptr to actual function type according to
99cac7dca0Sopenharmony_ci    // definition.
100cac7dca0Sopenharmony_ci    if act.sa_flags & libc::SA_SIGINFO == 0 {
101cac7dca0Sopenharmony_ci        let action = unsafe { mem::transmute::<usize, extern "C" fn(c_int)>(handler) };
102cac7dca0Sopenharmony_ci        action(sig_num);
103cac7dca0Sopenharmony_ci    } else {
104cac7dca0Sopenharmony_ci        type Action = extern "C" fn(c_int, *mut siginfo_t, *mut c_void);
105cac7dca0Sopenharmony_ci        let action = unsafe { mem::transmute::<usize, Action>(handler) };
106cac7dca0Sopenharmony_ci        action(sig_num, sig_info, data);
107cac7dca0Sopenharmony_ci    }
108cac7dca0Sopenharmony_ci}
109