1use ctrlc::set_handler;
6pub use ctrlc::Error;
7#[cfg(feature = "stream")]
8use futures_core::stream::Stream;
9use std::{
10 future::Future,
11 pin::Pin,
12 ptr::null_mut,
13 sync::atomic::{AtomicBool, AtomicPtr, Ordering},
14 task::{Context, Poll, Waker},
15};
16
17static WAKER: AtomicPtr<Waker> = AtomicPtr::new(null_mut());
20static ACTIVE: AtomicBool = AtomicBool::new(false);
21
22#[derive(Debug)]
24pub struct CtrlC {
25 _private: (),
26}
27
28impl Future for CtrlC {
29 type Output = ();
30 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
31 if ACTIVE.swap(false, Ordering::SeqCst) {
32 Poll::Ready(())
33 } else {
34 let new_waker = Box::new(cx.waker().clone());
35 let old_waker_ptr = WAKER.swap(Box::into_raw(new_waker), Ordering::SeqCst);
36 if !old_waker_ptr.is_null() {
37 unsafe { Box::from_raw(old_waker_ptr) };
38 }
39 Poll::Pending
40 }
41 }
42}
43
44#[cfg(feature = "stream")]
45impl Stream for CtrlC {
46 type Item = ();
47 fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
48 self.poll(cx).map(Some)
49 }
50}
51
52impl CtrlC {
53 pub fn new() -> Result<Self, Error> {
58 set_handler(|| {
59 ACTIVE.store(true, Ordering::SeqCst);
60 let waker_ptr = WAKER.swap(null_mut(), Ordering::SeqCst);
61 if !waker_ptr.is_null() {
62 unsafe { Box::from_raw(waker_ptr) }.wake();
63 }
64 })?;
65 Ok(CtrlC { _private: () })
66 }
67}
68
69#[cfg(unix)]
70#[test]
71fn test_unix() {
72 use async_std::{future::timeout, task::block_on};
73 use libc::{getpid, kill, SIGINT};
74 use std::{
75 thread::{sleep, spawn},
76 time::Duration,
77 };
78
79 let thread = spawn(|| unsafe {
80 sleep(Duration::from_millis(100));
81 kill(getpid(), SIGINT);
82 });
83
84 let c = CtrlC::new().unwrap();
85 let result = block_on(async move {
86 let i = 1;
87 timeout(Duration::from_millis(500), c).await.unwrap();
88 i + 2
89 });
90 assert_eq!(result, 3);
91
92 thread.join().unwrap();
93}