• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 //! Asynchronous signal handling in windows system.
15 
16 mod registry;
17 mod winapi;
18 
19 use std::io;
20 use std::sync::Once;
21 
22 use registry::Registry;
23 
24 use crate::signal::Signal;
25 
26 /// Signal kind to listen for.
27 #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
28 pub struct SignalKind(u32);
29 
30 impl SignalKind {
31     /// "ctrl-break" signal type.
32     ///
33     /// # Examples
34     ///
35     /// ```no_run
36     /// use ylong_runtime::signal::{signal, SignalKind};
37     /// async fn io_func() {
38     ///     let handle = ylong_runtime::spawn(async move {
39     ///         let mut signal = signal(SignalKind::ctrl_break()).unwrap();
40     ///         signal.recv().await;
41     ///     });
42     ///     let _ = ylong_runtime::block_on(handle);
43     /// }
44     /// ```
ctrl_break() -> SignalKind45     pub const fn ctrl_break() -> SignalKind {
46         SignalKind(winapi::CTRL_BREAK_EVENT)
47     }
48 
49     /// "ctrl-close" signal type.
50     ///
51     /// # Examples
52     ///
53     /// ```no_run
54     /// use ylong_runtime::signal::{signal, SignalKind};
55     /// async fn io_func() {
56     ///     let handle = ylong_runtime::spawn(async move {
57     ///         let mut signal = signal(SignalKind::ctrl_close()).unwrap();
58     ///         signal.recv().await;
59     ///     });
60     ///     let _ = ylong_runtime::block_on(handle);
61     /// }
62     /// ```
ctrl_close() -> SignalKind63     pub const fn ctrl_close() -> SignalKind {
64         SignalKind(winapi::CTRL_CLOSE_EVENT)
65     }
66 
67     /// "ctrl-c" signal type.
68     ///
69     /// # Examples
70     ///
71     /// ```no_run
72     /// use ylong_runtime::signal::{signal, SignalKind};
73     /// async fn io_func() {
74     ///     let handle = ylong_runtime::spawn(async move {
75     ///         let mut signal = signal(SignalKind::ctrl_c()).unwrap();
76     ///         signal.recv().await;
77     ///     });
78     ///     let _ = ylong_runtime::block_on(handle);
79     /// }
80     /// ```
ctrl_c() -> SignalKind81     pub const fn ctrl_c() -> SignalKind {
82         SignalKind(winapi::CTRL_C_EVENT)
83     }
84 
85     /// "ctrl-logoff" signal type.
86     ///
87     /// # Examples
88     ///
89     /// ```no_run
90     /// use ylong_runtime::signal::{signal, SignalKind};
91     /// async fn io_func() {
92     ///     let handle = ylong_runtime::spawn(async move {
93     ///         let mut signal = signal(SignalKind::ctrl_logoff()).unwrap();
94     ///         signal.recv().await;
95     ///     });
96     ///     let _ = ylong_runtime::block_on(handle);
97     /// }
98     /// ```
ctrl_logoff() -> SignalKind99     pub const fn ctrl_logoff() -> SignalKind {
100         SignalKind(winapi::CTRL_LOGOFF_EVENT)
101     }
102 
103     /// "ctrl-shutdown" signal type.
104     ///
105     /// # Examples
106     ///
107     /// ```no_run
108     /// use ylong_runtime::signal::{signal, SignalKind};
109     /// async fn io_func() {
110     ///     let handle = ylong_runtime::spawn(async move {
111     ///         let mut signal = signal(SignalKind::ctrl_shutdown()).unwrap();
112     ///         signal.recv().await;
113     ///     });
114     ///     let _ = ylong_runtime::block_on(handle);
115     /// }
116     /// ```
ctrl_shutdown() -> SignalKind117     pub const fn ctrl_shutdown() -> SignalKind {
118         SignalKind(winapi::CTRL_SHUTDOWN_EVENT)
119     }
120 }
121 
122 #[derive(Default)]
123 pub(crate) struct SignalStream;
124 
signal_action(signal_kind: u32) -> i32125 unsafe extern "system" fn signal_action(signal_kind: u32) -> i32 {
126     let global = Registry::get_instance();
127     global.broadcast(signal_kind as usize)
128 }
129 
init_signal() -> io::Result<()>130 fn init_signal() -> io::Result<()> {
131     static SIGNAL_ONCE: Once = Once::new();
132     let mut register_res = Ok(());
133     SIGNAL_ONCE.call_once(|| {
134         let res = unsafe { winapi::SetConsoleCtrlHandler(Some(signal_action), 1) };
135         register_res = if res != 0 {
136             Ok(())
137         } else {
138             Err(io::Error::last_os_error())
139         };
140     });
141     register_res
142 }
143 
144 /// Creates a listener for the specified signal type.
145 ///
146 /// # Errors
147 ///
148 /// * If signal processing function registration failed.
149 ///
150 /// # Examples
151 ///
152 /// ```no run
153 /// use ylong_runtime::signal::{signal, SignalKind};
154 /// async fn io_func() {
155 ///     let handle = ylong_runtime::spawn(async move {
156 ///         let mut signal = signal(SignalKind::child()).unwrap();
157 ///         signal.recv().await;
158 ///     });
159 ///     let _ = ylong_runtime::block_on(handle);
160 /// }
161 /// ```
signal(kind: SignalKind) -> io::Result<Signal>162 pub fn signal(kind: SignalKind) -> io::Result<Signal> {
163     init_signal()?;
164     let registry = Registry::get_instance();
165     Ok(Signal {
166         inner: registry.listen_to_event(kind.0 as usize),
167     })
168 }
169