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 mod driver;
17 mod registry;
18 
19 use std::io;
20 use std::io::{Error, ErrorKind};
21 use std::os::raw::c_int;
22 
23 pub(crate) use driver::SignalDriver;
24 use registry::Registry;
25 use ylong_signal::SIGNAL_BLOCK_LIST;
26 
27 use crate::signal::Signal;
28 use crate::sync::watch::Receiver;
29 
30 /// Signal kind to listen for.
31 #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
32 pub struct SignalKind(c_int);
33 
34 impl SignalKind {
get_max() -> i3235     pub(crate) fn get_max() -> i32 {
36         #[cfg(target_os = "linux")]
37         let max = libc::SIGRTMAX();
38         #[cfg(not(target_os = "linux"))]
39         let max = 33;
40         max
41     }
42 
43     /// Generates [`SignalKind`] from valid numeric value.
44     ///
45     /// # Examples
46     ///
47     /// ```no_run
48     /// use ylong_runtime::signal::{signal, SignalKind};
49     /// async fn io_func() {
50     ///     let signal_kind = SignalKind::from_raw(2);
51     ///     let handle = ylong_runtime::spawn(async move {
52     ///         let mut signal = signal(signal_kind).unwrap();
53     ///         signal.recv().await;
54     ///     });
55     ///     let _ = ylong_runtime::block_on(handle);
56     /// }
57     /// ```
from_raw(signal_num: c_int) -> SignalKind58     pub const fn from_raw(signal_num: c_int) -> SignalKind {
59         SignalKind(signal_num)
60     }
61 
62     /// Gets the numeric value.
63     ///
64     /// # Examples
65     ///
66     /// ```no_run
67     /// use ylong_runtime::signal::SignalKind;
68     /// async fn io_func() {
69     ///     let signal_kind = SignalKind::interrupt();
70     ///     assert_eq!(signal_kind.as_raw(), 2);
71     /// }
72     /// ```
as_raw(&self) -> c_int73     pub const fn as_raw(&self) -> c_int {
74         self.0
75     }
76 
77     /// SIGALRM signal.
78     ///
79     /// # Unix system
80     /// Raised when a timer expires, typically used for timing operations. By
81     /// default, it terminates the process.
82     ///
83     /// # Examples
84     ///
85     /// ```no_run
86     /// use ylong_runtime::signal::{signal, SignalKind};
87     /// async fn io_func() {
88     ///     let handle = ylong_runtime::spawn(async move {
89     ///         let mut signal = signal(SignalKind::alarm()).unwrap();
90     ///         signal.recv().await;
91     ///     });
92     ///     let _ = ylong_runtime::block_on(handle);
93     /// }
94     /// ```
alarm() -> SignalKind95     pub const fn alarm() -> SignalKind {
96         SignalKind(libc::SIGALRM as c_int)
97     }
98 
99     /// SIGCHLD signal.
100     ///
101     /// # Unix system
102     /// Received by the parent process when a child process terminates or stops.
103     /// By default, it is ignored.
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::child()).unwrap();
112     ///         signal.recv().await;
113     ///     });
114     ///     let _ = ylong_runtime::block_on(handle);
115     /// }
116     /// ```
child() -> SignalKind117     pub const fn child() -> SignalKind {
118         SignalKind(libc::SIGCHLD as c_int)
119     }
120 
121     /// SIGHUP signal.
122     ///
123     /// # Unix system
124     /// Raised when the terminal connection is disconnected, usually sent to all
125     /// members of the foreground process group. By default, it is ignored.
126     ///
127     /// # Examples
128     ///
129     /// ```no_run
130     /// use ylong_runtime::signal::{signal, SignalKind};
131     /// async fn io_func() {
132     ///     let handle = ylong_runtime::spawn(async move {
133     ///         let mut signal = signal(SignalKind::hangup()).unwrap();
134     ///         signal.recv().await;
135     ///     });
136     ///     let _ = ylong_runtime::block_on(handle);
137     /// }
138     /// ```
hangup() -> SignalKind139     pub const fn hangup() -> SignalKind {
140         SignalKind(libc::SIGHUP as c_int)
141     }
142 
143     /// SIGINT signal.
144     ///
145     /// # Unix system
146     /// Raised when the user interrupts the process. By default, it terminates
147     /// the process.
148     ///
149     /// # Examples
150     ///
151     /// ```no_run
152     /// use ylong_runtime::signal::{signal, SignalKind};
153     /// async fn io_func() {
154     ///     let handle = ylong_runtime::spawn(async move {
155     ///         let mut signal = signal(SignalKind::interrupt()).unwrap();
156     ///         signal.recv().await;
157     ///     });
158     ///     let _ = ylong_runtime::block_on(handle);
159     /// }
160     /// ```
interrupt() -> SignalKind161     pub const fn interrupt() -> SignalKind {
162         SignalKind(libc::SIGINT as c_int)
163     }
164 
165     /// SIGIO signal.
166     ///
167     /// # Unix system
168     /// Sent by the kernel to the process when I/O is available. By default,it
169     /// is ignored.
170     ///
171     /// # Examples
172     ///
173     /// ```no_run
174     /// use ylong_runtime::signal::{signal, SignalKind};
175     /// async fn io_func() {
176     ///     let handle = ylong_runtime::spawn(async move {
177     ///         let mut signal = signal(SignalKind::io()).unwrap();
178     ///         signal.recv().await;
179     ///     });
180     ///     let _ = ylong_runtime::block_on(handle);
181     /// }
182     /// ```
io() -> SignalKind183     pub const fn io() -> SignalKind {
184         SignalKind(libc::SIGIO as c_int)
185     }
186 
187     /// SIGPIPE signal.
188     ///
189     /// # Unix system
190     /// Sent by the kernel to the process when writing to a closed pipe or
191     /// socket. By default, it terminates the process.
192     ///
193     /// # Examples
194     ///
195     /// ```no_run
196     /// use ylong_runtime::signal::{signal, SignalKind};
197     /// async fn io_func() {
198     ///     let handle = ylong_runtime::spawn(async move {
199     ///         let mut signal = signal(SignalKind::pipe()).unwrap();
200     ///         signal.recv().await;
201     ///     });
202     ///     let _ = ylong_runtime::block_on(handle);
203     /// }
204     /// ```
pipe() -> SignalKind205     pub const fn pipe() -> SignalKind {
206         SignalKind(libc::SIGPIPE as c_int)
207     }
208 
209     /// SIGQUIT signal.
210     ///
211     /// # Unix system
212     /// Raised when the user requests process termination and generate a core
213     /// dump. By default, it terminates the process.
214     ///
215     /// # Examples
216     ///
217     /// ```no_run
218     /// use ylong_runtime::signal::{signal, SignalKind};
219     /// async fn io_func() {
220     ///     let handle = ylong_runtime::spawn(async move {
221     ///         let mut signal = signal(SignalKind::quit()).unwrap();
222     ///         signal.recv().await;
223     ///     });
224     ///     let _ = ylong_runtime::block_on(handle);
225     /// }
226     /// ```
quit() -> SignalKind227     pub const fn quit() -> SignalKind {
228         SignalKind(libc::SIGQUIT as c_int)
229     }
230 
231     /// SIGTERM signal.
232     ///
233     /// # Unix system
234     /// A termination signal sent by the user to the process. By default, it
235     /// terminates the process.
236     ///
237     /// # Examples
238     ///
239     /// ```no_run
240     /// use ylong_runtime::signal::{signal, SignalKind};
241     /// async fn io_func() {
242     ///     let handle = ylong_runtime::spawn(async move {
243     ///         let mut signal = signal(SignalKind::terminate()).unwrap();
244     ///         signal.recv().await;
245     ///     });
246     ///     let _ = ylong_runtime::block_on(handle);
247     /// }
248     /// ```
terminate() -> SignalKind249     pub const fn terminate() -> SignalKind {
250         SignalKind(libc::SIGTERM as c_int)
251     }
252 
253     /// SIGUSR1 signal.
254     ///
255     /// # Unix system
256     /// User-defined signal that can be used for custom operations. By default,
257     /// it terminates the process.
258     ///
259     /// # Examples
260     ///
261     /// ```no_run
262     /// use ylong_runtime::signal::{signal, SignalKind};
263     /// async fn io_func() {
264     ///     let handle = ylong_runtime::spawn(async move {
265     ///         let mut signal = signal(SignalKind::user_defined1()).unwrap();
266     ///         signal.recv().await;
267     ///     });
268     ///     let _ = ylong_runtime::block_on(handle);
269     /// }
270     /// ```
user_defined1() -> SignalKind271     pub const fn user_defined1() -> SignalKind {
272         SignalKind(libc::SIGUSR1 as c_int)
273     }
274 
275     /// SIGUSR2 signal.
276     ///
277     /// # Unix system
278     /// User-defined signal that can be used for custom operations. By default,
279     /// it terminates the process.
280     ///
281     /// # Examples
282     ///
283     /// ```no_run
284     /// use ylong_runtime::signal::{signal, SignalKind};
285     /// async fn io_func() {
286     ///     let handle = ylong_runtime::spawn(async move {
287     ///         let mut signal = signal(SignalKind::user_defined2()).unwrap();
288     ///         signal.recv().await;
289     ///     });
290     ///     let _ = ylong_runtime::block_on(handle);
291     /// }
292     /// ```
user_defined2() -> SignalKind293     pub const fn user_defined2() -> SignalKind {
294         SignalKind(libc::SIGUSR2 as c_int)
295     }
296 
297     /// SIGWINCH signal.
298     ///
299     /// # Unix system
300     /// Sent by the kernel to all members of the foreground process group when
301     /// the terminal window size changes. By default, it is ignored.
302     ///
303     /// # Examples
304     ///
305     /// ```no_run
306     /// use ylong_runtime::signal::{signal, SignalKind};
307     /// async fn io_func() {
308     ///     let handle = ylong_runtime::spawn(async move {
309     ///         let mut signal = signal(SignalKind::window_change()).unwrap();
310     ///         signal.recv().await;
311     ///     });
312     ///     let _ = ylong_runtime::block_on(handle);
313     /// }
314     /// ```
window_change() -> SignalKind315     pub const fn window_change() -> SignalKind {
316         SignalKind(libc::SIGWINCH as c_int)
317     }
318 
319     /// Checks whether the signal is forbidden.
320     ///
321     /// # Examples
322     ///
323     /// ```no_run
324     /// use ylong_runtime::signal::SignalKind;
325     /// async fn io_func() {
326     ///     // SIGSEGV
327     ///     let signal_kind = SignalKind::from_raw(11);
328     ///     assert!(signal_kind.is_forbidden());
329     /// }
330     /// ```
is_forbidden(&self) -> bool331     pub fn is_forbidden(&self) -> bool {
332         if self.0 < 0 || self.0 > SignalKind::get_max() {
333             return true;
334         }
335         SIGNAL_BLOCK_LIST.contains(&self.0)
336     }
337 }
338 
339 impl From<c_int> for SignalKind {
from(value: c_int) -> Self340     fn from(value: c_int) -> Self {
341         Self::from_raw(value)
342     }
343 }
344 
345 impl From<SignalKind> for c_int {
from(value: SignalKind) -> Self346     fn from(value: SignalKind) -> Self {
347         value.as_raw()
348     }
349 }
350 
351 /// A callback processing function registered for specific a signal kind.
352 ///
353 /// Operations in this method should be async-signal safe.
signal_action(signal_kind: c_int)354 fn signal_action(signal_kind: c_int) {
355     let global = Registry::get_instance();
356     global.notify_event(signal_kind as usize);
357     let _ = global.write(&[1]);
358 }
359 
signal_return_watch(kind: SignalKind) -> io::Result<Receiver<()>>360 pub(crate) fn signal_return_watch(kind: SignalKind) -> io::Result<Receiver<()>> {
361     if kind.is_forbidden() {
362         return Err(Error::new(ErrorKind::Other, "Invalid signal kind"));
363     }
364 
365     let registry = Registry::get_instance();
366     let event = registry.get_event(kind.0 as usize);
367     event.register(kind.0, move || signal_action(kind.0))?;
368     Ok(registry.listen_to_event(kind.0 as usize))
369 }
370 
371 /// Creates a listener for the specified signal type.
372 ///
373 /// # Notice
374 /// This method will create a streaming listener bound to the runtime, which
375 /// will replace the default platform processing behavior and it will not be
376 /// reset after the receiver is destroyed. The same signal can be registered
377 /// multiple times, and when the signal is triggered, all receivers will receive
378 /// a notification.
379 ///
380 /// # Errors
381 ///
382 /// * If signal processing function registration failed.
383 /// * If the signal is one of [`SIGNAL_BLOCK_LIST`].
384 ///
385 /// # Panics
386 ///
387 /// This function panics if there is no ylong_runtime in the environment.
388 ///
389 /// # Examples
390 ///
391 /// ```no_run
392 /// use ylong_runtime::signal::{signal, SignalKind};
393 /// async fn io_func() {
394 ///     let handle = ylong_runtime::spawn(async move {
395 ///         let mut signal = signal(SignalKind::child()).unwrap();
396 ///         signal.recv().await;
397 ///     });
398 ///     let _ = ylong_runtime::block_on(handle);
399 /// }
400 /// ```
signal(kind: SignalKind) -> io::Result<Signal>401 pub fn signal(kind: SignalKind) -> io::Result<Signal> {
402     #[cfg(feature = "ffrt")]
403     let _ = SignalDriver::get_mut_ref();
404     let receiver = signal_return_watch(kind)?;
405     Ok(Signal { inner: receiver })
406 }
407 
408 #[cfg(test)]
409 mod tests {
410     use std::os::raw::c_int;
411 
412     use ylong_signal::SIGNAL_BLOCK_LIST;
413 
414     use crate::futures::poll_fn;
415     use crate::signal::unix::signal_return_watch;
416     use crate::signal::{signal, SignalKind};
417 
418     /// UT test cases of `SignalKind` conversion.
419     ///
420     /// # Brief
421     /// 1. Check the trait `From<c_int>` for `SignalKind`.
422     /// 2. Check the trait `From<SignalKind>` for `c_int`.
423     /// 3. Check the method `from_raw` of `SignalKind`.
424     /// 4. Check the method `as_raw` of `SignalKind`.
425     #[test]
ut_signal_from_and_into_c_int()426     fn ut_signal_from_and_into_c_int() {
427         assert_eq!(SignalKind::from(1), SignalKind::hangup());
428         assert_eq!(c_int::from(SignalKind::hangup()), 1);
429         assert_eq!(SignalKind::from_raw(2), SignalKind::interrupt());
430         assert_eq!(SignalKind::interrupt().as_raw(), 2);
431     }
432 
433     /// UT test cases for `signal_return_watch` with forbidden input.
434     ///
435     /// # Brief
436     /// 1. Generate a forbidden kind of signal.
437     /// 2. Call `signal_return_watch` and check the result.
438     #[test]
ut_signal_forbidden_input()439     fn ut_signal_forbidden_input() {
440         let signal_kind = SignalKind::from_raw(SIGNAL_BLOCK_LIST[0]);
441         assert!(signal_return_watch(signal_kind).is_err());
442     }
443 
444     /// UT test cases for `recv` and `poll_recv`.
445     ///
446     /// # Brief
447     /// 1. Generate a kind of signal.
448     /// 2. Send notification signals and try receiving them through `recv` and
449     ///    `poll_recv`.
450     #[test]
ut_signal_recv_and_poll_recv()451     fn ut_signal_recv_and_poll_recv() {
452         let mut handles = Vec::new();
453         handles.push(crate::spawn(async move {
454             let mut signal = signal(SignalKind::alarm()).unwrap();
455             unsafe { libc::raise(libc::SIGALRM) };
456             signal.recv().await;
457         }));
458         handles.push(crate::spawn(async move {
459             let mut signal = signal(SignalKind::alarm()).unwrap();
460             unsafe { libc::raise(libc::SIGALRM) };
461             poll_fn(|cx| signal.poll_recv(cx)).await;
462         }));
463     }
464 
465     /// UT test cases for SIGALRM signal.
466     ///
467     /// # Brief
468     /// 1. Generate the SIGALRM signal.
469     /// 2. Check the function of `signal` for the SIGALRM signal.
470     #[test]
ut_signal_alarm()471     fn ut_signal_alarm() {
472         let handle = crate::spawn(async move {
473             let mut signal = signal(SignalKind::alarm()).unwrap();
474             unsafe { libc::raise(libc::SIGALRM) };
475             signal.recv().await;
476         });
477         let _ = crate::block_on(handle);
478     }
479 
480     /// UT test cases for SIGCHLD signal.
481     ///
482     /// # Brief
483     /// 1. Generate the SIGCHLD signal.
484     /// 2. Check the function of `signal` for the SIGCHLD signal.
485     #[test]
ut_signal_child()486     fn ut_signal_child() {
487         let handle = crate::spawn(async move {
488             let mut signal = signal(SignalKind::child()).unwrap();
489             unsafe { libc::raise(libc::SIGCHLD) };
490             signal.recv().await;
491         });
492         let _ = crate::block_on(handle);
493     }
494 
495     /// UT test cases for SIGHUP signal.
496     ///
497     /// # Brief
498     /// 1. Generate the SIGHUP signal.
499     /// 2. Check the function of `signal` for the SIGHUP signal.
500     #[test]
ut_signal_hangup()501     fn ut_signal_hangup() {
502         let handle = crate::spawn(async move {
503             let mut signal = signal(SignalKind::hangup()).unwrap();
504             unsafe { libc::raise(libc::SIGHUP) };
505             signal.recv().await;
506         });
507         let _ = crate::block_on(handle);
508     }
509 
510     /// UT test cases for SIGINT signal.
511     ///
512     /// # Brief
513     /// 1. Generate the SIGINT signal.
514     /// 2. Check the function of `signal` for the SIGINT signal.
515     #[test]
ut_signal_interrupt()516     fn ut_signal_interrupt() {
517         let handle = crate::spawn(async move {
518             let mut signal = signal(SignalKind::interrupt()).unwrap();
519             unsafe { libc::raise(libc::SIGINT) };
520             signal.recv().await;
521         });
522         let _ = crate::block_on(handle);
523     }
524 
525     /// UT test cases for SIGIO signal.
526     ///
527     /// # Brief
528     /// 1. Generate the SIGIO signal.
529     /// 2. Check the function of `signal` for the SIGIO signal.
530     #[test]
ut_signal_io()531     fn ut_signal_io() {
532         let handle = crate::spawn(async move {
533             let mut signal = signal(SignalKind::io()).unwrap();
534             unsafe { libc::raise(libc::SIGIO) };
535             signal.recv().await;
536         });
537         let _ = crate::block_on(handle);
538     }
539 
540     /// UT test cases for SIGPIPE signal.
541     ///
542     /// # Brief
543     /// 1. Generate the SIGPIPE signal.
544     /// 2. Check the function of `signal` for the SIGPIPE signal.
545     #[test]
ut_signal_pipe()546     fn ut_signal_pipe() {
547         let handle = crate::spawn(async move {
548             let mut signal = signal(SignalKind::pipe()).unwrap();
549             unsafe { libc::raise(libc::SIGPIPE) };
550             signal.recv().await;
551         });
552         let _ = crate::block_on(handle);
553     }
554 
555     /// UT test cases for SIGTERM signal.
556     ///
557     /// # Brief
558     /// 1. Generate the SIGTERM signal.
559     /// 2. Check the function of `signal` for the SIGTERM signal.
560     #[test]
ut_signal_terminate()561     fn ut_signal_terminate() {
562         let handle = crate::spawn(async move {
563             let mut signal = signal(SignalKind::terminate()).unwrap();
564             unsafe { libc::raise(libc::SIGTERM) };
565             signal.recv().await;
566         });
567         let _ = crate::block_on(handle);
568     }
569 
570     /// UT test cases for SIGUSR1 signal.
571     ///
572     /// # Brief
573     /// 1. Generate the SIGUSR1 signal.
574     /// 2. Check the function of `signal` for the SIGUSR1 signal.
575     #[test]
ut_signal_user_defined1()576     fn ut_signal_user_defined1() {
577         let handle = crate::spawn(async move {
578             let mut signal = signal(SignalKind::user_defined1()).unwrap();
579             unsafe { libc::raise(libc::SIGUSR1) };
580             signal.recv().await;
581         });
582         let _ = crate::block_on(handle);
583     }
584 
585     /// UT test cases for SIGUSR2 signal.
586     ///
587     /// # Brief
588     /// 1. Generate the SIGUSR2 signal.
589     /// 2. Check the function of `signal` for the SIGUSR2 signal.
590     #[test]
ut_signal_user_defined2()591     fn ut_signal_user_defined2() {
592         let handle = crate::spawn(async move {
593             let mut signal = signal(SignalKind::user_defined2()).unwrap();
594             unsafe { libc::raise(libc::SIGUSR2) };
595             signal.recv().await;
596         });
597         let _ = crate::block_on(handle);
598     }
599 
600     /// UT test cases for SIGWINCH signal.
601     ///
602     /// # Brief
603     /// 1. Generate the SIGWINCH signal.
604     /// 2. Check the function of `signal` for the SIGWINCH signal.
605     #[test]
ut_signal_window_change()606     fn ut_signal_window_change() {
607         let handle = crate::spawn(async move {
608             let mut signal = signal(SignalKind::window_change()).unwrap();
609             unsafe { libc::raise(libc::SIGWINCH) };
610             signal.recv().await;
611         });
612         let _ = crate::block_on(handle);
613     }
614 }
615