ctrlc/platform/unix/
mod.rs1use crate::error::Error as CtrlcError;
11
12#[cfg(not(target_vendor = "apple"))]
13#[allow(static_mut_refs)] mod implementation {
15 static mut SEMAPHORE: nix::libc::sem_t = unsafe { std::mem::zeroed() };
16 const SEM_THREAD_SHARED: nix::libc::c_int = 0;
17
18 pub unsafe fn sem_init() {
19 nix::libc::sem_init(&mut SEMAPHORE as *mut _, SEM_THREAD_SHARED, 0);
20 }
21
22 pub unsafe fn sem_post() {
23 let _ = nix::libc::sem_post(&mut SEMAPHORE as *mut _);
25 }
26
27 pub unsafe fn sem_wait_forever() {
28 while nix::libc::sem_wait(&mut SEMAPHORE as *mut _) == -1 {}
30 }
31}
32
33#[cfg(target_vendor = "apple")]
34mod implementation {
35 use dispatch2::{DispatchRetained, DispatchSemaphore, DispatchTime};
36
37 static mut SEMAPHORE: Option<DispatchRetained<DispatchSemaphore>> = None;
38
39 pub unsafe fn sem_init() {
40 SEMAPHORE = Some(DispatchSemaphore::new(0));
41 }
42
43 #[allow(static_mut_refs)]
44 pub unsafe fn sem_post() {
45 SEMAPHORE.as_deref().unwrap().signal();
46 }
47
48 #[allow(static_mut_refs)]
49 pub unsafe fn sem_wait_forever() {
50 SEMAPHORE.as_deref().unwrap().wait(DispatchTime::FOREVER);
51 }
52}
53
54pub type Error = nix::Error;
56
57pub type Signal = nix::sys::signal::Signal;
59
60extern "C" fn os_handler(_: nix::libc::c_int) {
61 unsafe {
62 implementation::sem_post();
63 }
64}
65
66#[inline]
75pub unsafe fn init_os_handler(overwrite: bool) -> Result<(), Error> {
76 use nix::sys::signal;
77
78 implementation::sem_init();
79
80 let handler = signal::SigHandler::Handler(os_handler);
81 #[cfg(not(target_os = "nto"))]
82 let new_action = signal::SigAction::new(
83 handler,
84 signal::SaFlags::SA_RESTART,
85 signal::SigSet::empty(),
86 );
87 #[cfg(target_os = "nto")]
89 let new_action =
90 signal::SigAction::new(handler, signal::SaFlags::empty(), signal::SigSet::empty());
91
92 let sigint_old = signal::sigaction(signal::Signal::SIGINT, &new_action)?;
93 if !overwrite && sigint_old.handler() != signal::SigHandler::SigDfl {
94 signal::sigaction(signal::Signal::SIGINT, &sigint_old).unwrap();
95 return Err(nix::Error::EEXIST);
96 }
97
98 #[cfg(feature = "termination")]
99 {
100 let sigterm_old = match signal::sigaction(signal::Signal::SIGTERM, &new_action) {
101 Ok(old) => old,
102 Err(e) => {
103 signal::sigaction(signal::Signal::SIGINT, &sigint_old).unwrap();
104 return Err(e);
105 }
106 };
107 if !overwrite && sigterm_old.handler() != signal::SigHandler::SigDfl {
108 signal::sigaction(signal::Signal::SIGINT, &sigint_old).unwrap();
109 signal::sigaction(signal::Signal::SIGTERM, &sigterm_old).unwrap();
110 return Err(nix::Error::EEXIST);
111 }
112 let sighup_old = match signal::sigaction(signal::Signal::SIGHUP, &new_action) {
113 Ok(old) => old,
114 Err(e) => {
115 signal::sigaction(signal::Signal::SIGINT, &sigint_old).unwrap();
116 signal::sigaction(signal::Signal::SIGTERM, &sigterm_old).unwrap();
117 return Err(e);
118 }
119 };
120 if !overwrite && sighup_old.handler() != signal::SigHandler::SigDfl {
121 signal::sigaction(signal::Signal::SIGINT, &sigint_old).unwrap();
122 signal::sigaction(signal::Signal::SIGTERM, &sigterm_old).unwrap();
123 signal::sigaction(signal::Signal::SIGHUP, &sighup_old).unwrap();
124 return Err(nix::Error::EEXIST);
125 }
126 }
127
128 Ok(())
129}
130
131#[inline]
139pub unsafe fn block_ctrl_c() -> Result<(), CtrlcError> {
140 implementation::sem_wait_forever();
141 Ok(())
142}