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//! windows wrapping of signal syscall
15cac7dca0Sopenharmony_ci
16cac7dca0Sopenharmony_ciuse std::{io, mem};
17cac7dca0Sopenharmony_ci
18cac7dca0Sopenharmony_ciuse libc::{c_int, sighandler_t, SIGFPE, SIG_DFL, SIG_ERR, SIG_GET, SIG_IGN};
19cac7dca0Sopenharmony_ci
20cac7dca0Sopenharmony_ciuse crate::common::{siginfo_t, 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 old_act = unsafe { libc::signal(sig_num, SIG_GET) };
26cac7dca0Sopenharmony_ci        if old_act == SIG_ERR as sighandler_t {
27cac7dca0Sopenharmony_ci            return Err(io::Error::last_os_error());
28cac7dca0Sopenharmony_ci        }
29cac7dca0Sopenharmony_ci        Ok(SigAction {
30cac7dca0Sopenharmony_ci            sig_num,
31cac7dca0Sopenharmony_ci            act: old_act,
32cac7dca0Sopenharmony_ci        })
33cac7dca0Sopenharmony_ci    }
34cac7dca0Sopenharmony_ci}
35cac7dca0Sopenharmony_ci
36cac7dca0Sopenharmony_ciimpl Signal {
37cac7dca0Sopenharmony_ci    pub(crate) fn replace_sigaction(
38cac7dca0Sopenharmony_ci        sig_num: c_int,
39cac7dca0Sopenharmony_ci        new_action: sighandler_t,
40cac7dca0Sopenharmony_ci    ) -> io::Result<sighandler_t> {
41cac7dca0Sopenharmony_ci        let old_act = unsafe { libc::signal(sig_num, new_action) };
42cac7dca0Sopenharmony_ci
43cac7dca0Sopenharmony_ci        if old_act == SIG_ERR as sighandler_t {
44cac7dca0Sopenharmony_ci            return Err(io::Error::last_os_error());
45cac7dca0Sopenharmony_ci        }
46cac7dca0Sopenharmony_ci
47cac7dca0Sopenharmony_ci        Ok(old_act)
48cac7dca0Sopenharmony_ci    }
49cac7dca0Sopenharmony_ci}
50cac7dca0Sopenharmony_ci
51cac7dca0Sopenharmony_cipub(crate) extern "C" fn sig_handler(sig_num: c_int) {
52cac7dca0Sopenharmony_ci    if sig_num != SIGFPE {
53cac7dca0Sopenharmony_ci        let old = unsafe { libc::signal(sig_num, sig_handler as usize) };
54cac7dca0Sopenharmony_ci        if old == SIG_ERR as sighandler_t {
55cac7dca0Sopenharmony_ci            unsafe {
56cac7dca0Sopenharmony_ci                libc::abort();
57cac7dca0Sopenharmony_ci            }
58cac7dca0Sopenharmony_ci        }
59cac7dca0Sopenharmony_ci    }
60cac7dca0Sopenharmony_ci
61cac7dca0Sopenharmony_ci    let sig_map = SigMap::get_instance();
62cac7dca0Sopenharmony_ci    let race_fallback = sig_map.race_old.read();
63cac7dca0Sopenharmony_ci    let data = sig_map.data.read();
64cac7dca0Sopenharmony_ci
65cac7dca0Sopenharmony_ci    if let Some(signal) = data.get(&sig_num) {
66cac7dca0Sopenharmony_ci        if let Some(act) = &signal.new_act {
67cac7dca0Sopenharmony_ci            act(&siginfo_t);
68cac7dca0Sopenharmony_ci        }
69cac7dca0Sopenharmony_ci    } else if let Some(fallback) = race_fallback.as_ref() {
70cac7dca0Sopenharmony_ci        // There could be a race condition between swapping the old handler with the new
71cac7dca0Sopenharmony_ci        // handler and storing the change back to the global during the register
72cac7dca0Sopenharmony_ci        // procedure. Because of the race condition, the old handler and the new
73cac7dca0Sopenharmony_ci        // action could both not get executed. In order to prevent this, we
74cac7dca0Sopenharmony_ci        // store the old handler into global before swapping the handler in
75cac7dca0Sopenharmony_ci        // register. And during the handler execution, if the the action
76cac7dca0Sopenharmony_ci        // of the signal cannot be found, we execute this old handler instead if the
77cac7dca0Sopenharmony_ci        // sig_num matches.
78cac7dca0Sopenharmony_ci        if fallback.sig_num == sig_num {
79cac7dca0Sopenharmony_ci            execute_act(fallback.act, sig_num);
80cac7dca0Sopenharmony_ci        }
81cac7dca0Sopenharmony_ci    }
82cac7dca0Sopenharmony_ci}
83cac7dca0Sopenharmony_ci
84cac7dca0Sopenharmony_cifn execute_act(act: sighandler_t, sig_num: c_int) {
85cac7dca0Sopenharmony_ci    if act != 0 && act != SIG_DFL && act != SIG_IGN {
86cac7dca0Sopenharmony_ci        unsafe {
87cac7dca0Sopenharmony_ci            let action = mem::transmute::<usize, extern "C" fn(c_int)>(act);
88cac7dca0Sopenharmony_ci            action(sig_num);
89cac7dca0Sopenharmony_ci        }
90cac7dca0Sopenharmony_ci    }
91cac7dca0Sopenharmony_ci}
92