1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
//! Asynchronous signal handling.

/// Completes when a "ctrl-c" notification is sent to the process.
pub async fn ctrl_c() -> std::io::Result<()> {
    let mut rx = crate::context::current_task().node.ctrl_c();
    _ = rx.changed().await;
    Ok(())
}

#[cfg(test)]
mod tests {
    use crate::{
        runtime::{Handle, Runtime},
        time,
    };
    use futures_util::future::pending;
    use std::sync::{
        atomic::{AtomicBool, Ordering},
        Arc,
    };
    use std::time::Duration;

    #[test]
    fn ctrl_c_kill() {
        let runtime = Runtime::new();
        let node = runtime.create_node().build();

        runtime.block_on(async move {
            let h = node.spawn(async {
                pending::<()>().await;
            });
            assert!(!h.is_finished());

            // ctrl-c will kill the node
            Handle::current().send_ctrl_c(node.id());

            time::sleep(Duration::from_secs(1)).await;
            assert!(h.is_finished());
        });
    }

    #[test]
    fn ctrl_c_catch() {
        let runtime = Runtime::new();
        let node = runtime.create_node().build();

        runtime.block_on(async move {
            for _ in 0..2 {
                let flag = Arc::new(AtomicBool::new(false));
                let flag1 = flag.clone();

                let h = node.spawn(async move {
                    crate::signal::ctrl_c().await.unwrap();
                    flag1.store(true, Ordering::Relaxed);
                    pending::<()>().await;
                });
                time::sleep(Duration::from_secs(1)).await;
                assert!(!flag.load(Ordering::Relaxed));
                assert!(!h.is_finished());

                // ctrl-c will be caught and not kill the node
                Handle::current().send_ctrl_c(node.id());

                time::sleep(Duration::from_secs(1)).await;
                assert!(flag.load(Ordering::Relaxed));
                assert!(!h.is_finished());
            }
        });
    }
}