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.
15 
16 #[cfg(unix)]
17 pub mod unix;
18 #[cfg(unix)]
19 pub use unix::{signal, SignalKind};
20 
21 #[cfg(target_os = "windows")]
22 pub mod windows;
23 use std::task::{Context, Poll};
24 
25 #[cfg(target_os = "windows")]
26 pub use windows::{signal, SignalKind};
27 
28 use crate::sync::watch::Receiver;
29 
30 /// A listener for monitoring operating system signals.
31 ///
32 /// # Unix
33 /// This listener will merge signals of the same kind and receive them in a
34 /// stream, so for multiple triggers of the same signal, the receiver may only
35 /// receive one notification, which includes all triggered signal kinds.
36 ///
37 /// When registering a listener for a certain kind of signal for the first time,
38 /// it will replace the default platform processing behavior. If some process
39 /// termination signals are triggered, the process will not be terminated
40 /// immediately, but will merge the signals into the stream and trigger them
41 /// uniformly, which will be captured and processed by the corresponding
42 /// receiver. Deconstructing the receiver does not reset the default platform
43 /// processing behavior.
44 ///
45 /// # Examples
46 /// On Windows system
47 ///
48 /// ```no run
49 /// use ylong_runtime::signal::{signal, SignalKind};
50 /// async fn io_func() {
51 ///     let handle = ylong_runtime::spawn(async move {
52 ///         let mut signal = signal(SignalKind::ctrl_c()).unwrap();
53 ///         signal.recv().await;
54 ///     });
55 ///     let _ = ylong_runtime::block_on(handle);
56 /// }
57 /// ```
58 ///
59 /// On Unix system
60 ///
61 /// ```no run
62 /// use ylong_runtime::signal::{signal, SignalKind};
63 /// async fn io_func() {
64 ///     let handle = ylong_runtime::spawn(async move {
65 ///         let mut signal = signal(SignalKind::child()).unwrap();
66 ///         signal.recv().await;
67 ///     });
68 ///     let _ = ylong_runtime::block_on(handle);
69 /// }
70 /// ```
71 pub struct Signal {
72     inner: Receiver<()>,
73 }
74 
75 impl Signal {
76     /// Waits for signal notification.
77     ///
78     /// # Examples
79     /// On Windows system
80     ///
81     /// ```no run
82     /// use ylong_runtime::signal::{signal, SignalKind};
83     /// async fn io_func() {
84     ///     let handle = ylong_runtime::spawn(async move {
85     ///         let mut signal = signal(SignalKind::ctrl_c()).unwrap();
86     ///         signal.recv().await;
87     ///     });
88     ///     let _ = ylong_runtime::block_on(handle);
89     /// }
90     /// ```
91     ///
92     /// On Unix system
93     ///
94     /// ```no run
95     /// use ylong_runtime::signal::{signal, SignalKind};
96     /// async fn io_func() {
97     ///     let handle = ylong_runtime::spawn(async move {
98     ///         let mut signal = signal(SignalKind::child()).unwrap();
99     ///         signal.recv().await;
100     ///     });
101     ///     let _ = ylong_runtime::block_on(handle);
102     /// }
103     /// ```
recv(&mut self)104     pub async fn recv(&mut self) {
105         // The sender is saved in the registry of the global singleton and should not be
106         // deconstructed.
107         self.inner
108             .notified()
109             .await
110             .unwrap_or_else(|e| panic!("Signal sender has been dropped, error: {e}"));
111     }
112 
113     /// Polls to waits for signal notification.
114     ///
115     /// # Return value
116     /// * `Poll::Pending` if no notification comes.
117     /// * `Poll::Ready(())` if receiving a new signal notification.
118     ///
119     /// # Examples
120     /// On Windows system
121     ///
122     /// ```no run
123     /// use ylong_runtime::futures::poll_fn;
124     /// use ylong_runtime::signal::{signal, SignalKind};
125     /// async fn io_func() {
126     ///     let handle = ylong_runtime::spawn(async move {
127     ///         let mut signal = signal(SignalKind::ctrl_c()).unwrap();
128     ///         poll_fn(|cx| signal.poll_recv(cx)).await;
129     ///     });
130     ///     let _ = ylong_runtime::block_on(handle);
131     /// }
132     /// ```
133     ///
134     /// On Unix system
135     ///
136     /// ```no run
137     /// use ylong_runtime::futures::poll_fn;
138     /// use ylong_runtime::signal::{signal, SignalKind};
139     /// async fn io_func() {
140     ///     let handle = ylong_runtime::spawn(async move {
141     ///         let mut signal = signal(SignalKind::child()).unwrap();
142     ///         poll_fn(|cx| signal.poll_recv(cx)).await;
143     ///     });
144     ///     let _ = ylong_runtime::block_on(handle);
145     /// }
146     /// ```
poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<()>147     pub fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<()> {
148         // The sender is saved in the registry of the global singleton and should not be
149         // deconstructed.
150         match self.inner.poll_notified(cx) {
151             Poll::Ready(Ok(())) => Poll::Ready(()),
152             Poll::Ready(Err(_)) => panic!("Signal sender has been dropped"),
153             Poll::Pending => Poll::Pending,
154         }
155     }
156 }
157