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