1// Copyright (c) 2023 Huawei Device Co., Ltd.
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6//     http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14#![warn(missing_docs)]
15
16//! # ylong_signal
17//! Provides methods to set or unset an action for signal handler.
18
19mod common;
20pub use common::SIGNAL_BLOCK_LIST;
21
22mod sig_map;
23mod spin_rwlock;
24#[cfg(windows)]
25mod windows;
26
27#[cfg(not(windows))]
28mod unix;
29
30use std::io;
31
32use libc::c_int;
33
34/// Registers a user-defined function for the signal action.
35///
36/// Currently this function only supports registering one action for each
37/// signal. If another component in the process sets a signal action
38/// without using this method, this old action will be overwritten by the
39/// new registered action. After unregistering this old action will
40/// in turn overwrite the new registered ation.
41/// # Errors
42///
43/// Calling this fuction twice on the same signal without a call to
44/// [`deregister_signal_action`] will result in an `AlreadyExists` error.
45///
46/// Calling this function on the following signal will result in a
47/// `InvalidInput` error:
48/// - `SIGSEGV`
49/// - `SIGKILL`
50/// - `SIGSTOP`
51/// - `SIGFPE`
52/// - `SIGILL`
53/// This function doesn't support setting actions for these signals due to POSIX
54/// settings or their needs of special handling.
55///
56/// # Safety
57///
58/// This function is unsafe, because it sets a function to be run in a signal
59/// handler as there are a lot of limitations (async-signal-safe) on what you
60/// can do inside a signal handler. For example, you should not use blocking
61/// Mutex since it could cause the program become deadlocked.
62///
63/// # Example
64/// ```no run
65/// let res = unsafe {
66///     ylong_signal::register_signal_action(libc::SIGTERM, move || {
67///         println!("inside SIGTERM signal handler");
68///     })
69/// };
70/// assert!(res.is_ok());
71/// ```
72pub unsafe fn register_signal_action<F>(sig_num: c_int, handler: F) -> io::Result<()>
73where
74    F: Fn() + Sync + Send + 'static,
75{
76    common::Signal::register_action(sig_num, move |_| handler())
77}
78
79/// Deregisters the signal action set to a specific signal by a previous call to
80/// [`register_signal_action`].
81///
82/// If the signal passed in has not been set before by
83/// [`register_signal_action`], this function will do nothing.
84///
85/// If the signal passed in has been set before by [`register_signal_action`],
86/// then the action of the signal will be dropped, and the overwritten old
87/// action will take its place. The overwrite action may fail and return an
88/// error.
89///
90/// After calling this function, you could call [`register_signal_action`] again
91/// on the same signal.
92///
93/// # Example
94/// ```no run
95/// ylong_signal::deregister_signal_action(libc::SIGTERM);
96/// ```
97pub fn deregister_signal_action(sig_num: c_int) -> io::Result<()> {
98    common::Signal::deregister_action(sig_num)
99}
100
101/// Deregisters the signal handler of a signal along with all its previous
102/// registered actions.
103///
104/// The remove of the signal handler will influence all components inside the
105/// process, therefore you should be cautious when calling this function.
106///
107/// # Example
108/// ```no run
109/// let res = ylong_signal::deregister_signal_hook(libc::SIGTERM);
110/// assert!(res.is_ok());
111/// ```
112pub fn deregister_signal_hook(sig_num: c_int) -> io::Result<()> {
113    common::Signal::deregister_hook(sig_num)
114}
115