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