addy/lib.rs
1//! # Addy
2//! A library for ergonomically handling kernel interrupts.
3//!
4//! ## Quick Start
5//! ```no_run
6//! use addy::SIGWINCH;
7//! use std::io::{Read, stdin};
8//! fn main() -> Result<(), addy::Error> {
9//! /* SIGWINCH is a POSIX interrupt signal for window resized */
10//! addy::mediate(SIGWINCH)
11//! .register("print", |_signal| { println!("Screen Resized!"); })?
12//! .enable()?;
13//!
14//! /* Block so the program doesn't exit immediately
15//! * Try resizing your terminal window :)
16//! */
17//! let mut buffer = [0; 1];
18//! loop {
19//! stdin().read(&mut buffer);
20//! }
21//! Ok(())
22//! }
23//! ```
24//!
25//! # Things To Know
26//! I love you and I wish the best for you. No matter what you choose to do, I hope you decide it is worth you time to do it well.
27//!
28//! ## Addy is Thread Safe!
29//! You can call it from anywhere, at anytime! You can store a SignalHandle (returned from addy::mediate(signal)) in a variable and pass it around.
30//! ```no_run
31//! use addy::{SIGWINCH, SIGINT};
32//! use std::io::{Read, stdin};
33//! static QUOTE: &'static str = "Look at you, hacker: a pathetic creature of meat \
34//! and bone, panting and sweating as you run through \
35//! my corridors. How can you challenge a perfect, \
36//! immortal machine?";
37//!
38//! fn main() -> Result<(), addy::Error> {
39//! /* When the window resizes */
40//! addy::mediate(SIGWINCH)
41//! .register("hello", |_signal| { println!("Hello, World!"); })?
42//! .register("girls", |_signal| { println!("Hello, Girls!"); })?
43//! .enable()?;
44//!
45//! /* SIGINT is sent when the user presses Ctrl + C. The default behavior is
46//! * to interrupt the program's execution.
47//! */
48//! let mut ctrl_c = addy::mediate(SIGINT);
49//! ctrl_c.register("no_interruptions", |_signal| { println!("{}", QUOTE); })?.enable()?;
50//!
51//! /* Let the user use Ctrl + C to kill the program after 10 seconds */
52//! std::thread::spawn(move || -> Result<(), addy::Error> {
53//! std::thread::sleep(std::time::Duration::from_secs(10));
54//! ctrl_c.default()?;
55//! Ok(())
56//! });
57//!
58//! /* Stop saying "Hello, World!" on resize after 5 seconds */
59//! std::thread::spawn(move || -> Result<(), addy::Error> {
60//! std::thread::sleep(std::time::Duration::from_secs(5));
61//! addy::mediate(SIGWINCH).remove("hello")?;
62//! Ok(())
63//! });
64//!
65//! /* Capture the input so we don't exit the program immediately */
66//! let mut buffer = [0; 1];
67//! loop {
68//! stdin().read(&mut buffer);
69//! }
70//!
71//! Ok(())
72//! }
73//! ```
74//! ## Errors
75//! If the MPSC channel closes, of the Event Loop thread closes, there is no way to recover and any future Addy calls will return an addy::Error.
76
77#![deny(
78 missing_docs,
79 missing_debug_implementations,
80 missing_copy_implementations,
81 trivial_casts,
82 trivial_numeric_casts,
83 unstable_features,
84 unused_import_braces,
85 unused_qualifications
86)]
87
88/* Standard Library */
89use std::convert::TryFrom;
90use std::sync::{
91 mpsc::{self, Sender},
92 Mutex, Once,
93};
94use std::thread;
95
96/* Std Lib Adjacent Crates */
97use lazy_static::lazy_static;
98use libc;
99
100/* Thrid Party Crates */
101use fnv::FnvHashMap; // Faster for the interger keys we're using
102
103/**********
104 * ERRORS *
105 **********/
106/* Use our own error instead of passing the SendError<Action> so we don't have
107 * expose the Action enum publicly.
108*/
109#[derive(Debug, Clone, Copy)]
110/// Addy Error type - realistically you will never see it. As it only occurs
111/// when the MPSC channel fails. MPSC channels only fail if the receiver is
112/// dropped which can only happen if the event loop thread panics somehow.
113///
114/// If it does fail, there is no way to recover, future Addy calls will fail.
115pub enum Error {
116 /// Returned when a function call on a SignalHandler fails.
117 CallFailed,
118}
119
120impl std::fmt::Display for Error {
121 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
122 match self {
123 Error::CallFailed => write!(
124 f,
125 "Addy function call failed to send. The MPSC and/or event loop thread has closed."
126 ),
127 }
128 }
129}
130
131impl std::error::Error for Error {
132 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
133 None
134 }
135}
136
137/***********
138 * ACTIONS *
139 ***********/
140
141/* Used by the MPSC channel to instruct what the Event Loop should do when
142 * it wakes up.
143 *
144 * ==========================================================================
145 *
146 * CBPointer is a how Addy represents "pointers" to the callbacks the caller
147 * passes in with .register()
148 *
149 * CBP wraps CBPointer so Debug can be implemented for it
150*/
151type CBPointer = Box<dyn Fn(Signal) -> () + Send>;
152struct CBP(CBPointer);
153impl std::fmt::Debug for CBP {
154 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
155 f.write_str("CBPointer")
156 }
157}
158
159/* This enum is what is message passed to the Event Loop to tell it what
160 * action to take.
161*/
162#[derive(Debug)]
163enum Action {
164 // Used by fn c_handler(...) to tell the Event Loop an interrupt occured
165 Call(Signal),
166 // Used by SignalHandle to add a named callback for the associated interrupt
167 Register(Signal, String, CBP),
168 // Used by SignalHandle to remove a named callback from the associated interrupt
169 Remove(Signal, String),
170 /* Used by SignalHandle to clear all the callbacks from the associated
171 * intterupt. This effectively ignores the interrupt, but the signal is
172 * still handled by this library and the signal handler. If you're clearing
173 * to stop callbacks, but don't plan on adding anymore use Release instead.
174 */
175 Clear(Signal),
176 // Used by SignalHandle to prevent the default signal behavior from occurring
177 Ignore(Signal),
178 /* Used by SignalHandle to restore the interrupt handler to the default
179 * behavior (like terminating your program). Some interrupt's default
180 * behavior is to be ignored.
181 */
182 Default(Signal),
183 /* Used by SignalHandle to stop handling the associated interrupt. Resets
184 * the interrupts behavior to default and clears all callbacks.
185 */
186 Release(Signal),
187 /* Used by SignalHandle to tell Addy to resume handling this intterupt.
188 * e.g. if you registered 3 callbacks, then set the interrupt handler to
189 * .ignore() or .default(), then later called .resume() the 3 callbacks
190 * would be called again when the interrupt occurs.
191 *
192 * This is also aliased by SignalHandle .enable() to start capturing the
193 * interrupt.
194 */
195 Resume(Signal),
196}
197
198/***********
199 * SIGNALS *
200 ***********/
201
202/* Most of this section is ripped & modified from the nix* crate so I didn't
203 * have to retype every signal and look up every architecture difference.
204 *
205 * Crate: https://crates.io/crates/nix
206 * Source: https://github.com/nix-rust/nix/blob/7a5248c70a4ad0ef1ff1b385a7674b38403386df/src/sys/signal.rs#L20
207 * License: (MIT) - https://github.com/nix-rust/nix/blob/master/LICENSE
208 *
209 * Representing the Signals as i32 (libc::c_int) so we can use Rust's features
210 * around enums.
211*/
212
213/* Required to we can use them in our callback HashMaps */
214/// Enum representing the different interrupt signals
215///
216/// # Signals Supported
217/// Not all signals are supported on all platforms/architectures. Which signals
218/// does your platform support? Run: `kill -l` to find out!
219///
220/// * SIGHUP
221/// * SIGINT
222/// * SIGQUIT
223/// * SIGILL
224/// * SIGTRAP
225/// * SIGABRT
226/// * SIGBUS
227/// * SIGFPE
228/// * SIGKILL
229/// * SIGUSR1
230/// * SIGSEGV
231/// * SIGUSR2
232/// * SIGPIPE
233/// * SIGALRM
234/// * SIGTERM
235/// * SIGSTKF
236/// * SIGCHLD
237/// * SIGCONT
238/// * SIGSTOP
239/// * SIGTSTP
240/// * SIGTTIN
241/// * SIGTTOU
242/// * SIGURG
243/// * SIGXCPU
244/// * SIGXFSZ
245/// * SIGVTAL
246/// * SIGPROF
247/// * SIGWINC
248/// * SIGIO
249/// * SIGPWR
250/// * SIGSYS
251/// * SIGEMT
252/// * SIGINFO
253#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
254#[repr(i32)]
255pub enum Signal {
256 /// Hangup detected on controlling terminal or death of controlling process
257 SIGHUP = libc::SIGHUP,
258 /// Interrupt from keyboard
259 SIGINT = libc::SIGINT,
260 /// Quit from keyboard
261 SIGQUIT = libc::SIGQUIT,
262 /// Illegal Instruction
263 SIGILL = libc::SIGILL,
264 /// Trace/breakpoint trap
265 SIGTRAP = libc::SIGTRAP,
266 /// Abort signal from abort(3)
267 SIGABRT = libc::SIGABRT,
268 /// Bus error (bad memory access)
269 SIGBUS = libc::SIGBUS,
270 /// Floating-point exception
271 SIGFPE = libc::SIGFPE,
272 /// Kill signal
273 SIGKILL = libc::SIGKILL,
274 /// User-defined signal 1
275 SIGUSR1 = libc::SIGUSR1,
276 /// Invalid memory reference
277 SIGSEGV = libc::SIGSEGV,
278 /// User-defined signal 2
279 SIGUSR2 = libc::SIGUSR2,
280 /// Broken pipe: write to pipe with no readers
281 SIGPIPE = libc::SIGPIPE,
282 /// Timer signal from alarm(2)
283 SIGALRM = libc::SIGALRM,
284 /// Termination signal
285 SIGTERM = libc::SIGTERM,
286 /// Stack fault on coprocessor.
287 #[cfg(all(
288 any(target_os = "android", target_os = "emscripten", target_os = "linux"),
289 not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))
290 ))]
291 SIGSTKFLT = libc::SIGSTKFLT,
292 /// Child stopped or terminated
293 SIGCHLD = libc::SIGCHLD,
294 /// Continue if stopped
295 SIGCONT = libc::SIGCONT,
296 /// Stop process
297 SIGSTOP = libc::SIGSTOP,
298 /// Stop typed at terminal
299 SIGTSTP = libc::SIGTSTP,
300 /// Terminal input for background process
301 SIGTTIN = libc::SIGTTIN,
302 /// Terminal output for background process
303 SIGTTOU = libc::SIGTTOU,
304 /// Urgent condition on socket (4.2BSD)
305 SIGURG = libc::SIGURG,
306 /// CPU time limit exceeded (4.2BSD)
307 SIGXCPU = libc::SIGXCPU,
308 /// File size limit exceeded (4.2BSD)
309 SIGXFSZ = libc::SIGXFSZ,
310 /// Virtual alarm clock (4.2BSD)
311 SIGVTALRM = libc::SIGVTALRM,
312 /// Profiling timer expired
313 SIGPROF = libc::SIGPROF,
314 /// Window resize signal (4.3BSD, Sun)
315 SIGWINCH = libc::SIGWINCH,
316 /// I/O now possible (4.2BSD)
317 SIGIO = libc::SIGIO,
318 /// Power failure (System V)
319 #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux"))]
320 SIGPWR = libc::SIGPWR,
321 /// Bad system call (SVr4)
322 SIGSYS = libc::SIGSYS,
323 /// Emulator trap
324 #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
325 SIGEMT = libc::SIGEMT,
326 /// A synonym for SIGPWR
327 #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
328 SIGINFO = libc::SIGINFO,
329}
330
331/* Re-export all the Signals without the prefix.
332 * Mad that I didn't know you could do this, I had a Signal enum and switched to
333 * constants for aesthetic reasons.
334*/
335pub use self::Signal::*;
336
337impl Signal {
338 /* Used so Signal can implement Display */
339
340 /// Returns name of signal.
341 ///
342 /// This function is equivalent to `<Signal as AsRef<str>>::as_ref()`,
343 /// with difference that returned string is `'static`
344 /// and not bound to `self`'s lifetime.
345 ///
346 /// # Example
347 /// ```
348 /// use addy::SIGINT;
349 ///
350 /// fn main() {
351 /// println!("My favorite interrupt is: {}", SIGINT);
352 /// }
353 /// ```
354 pub fn as_str(self) -> &'static str {
355 match self {
356 SIGHUP => "SIGHUP",
357 SIGINT => "SIGINT",
358 SIGQUIT => "SIGQUIT",
359 SIGILL => "SIGILL",
360 SIGTRAP => "SIGTRAP",
361 SIGABRT => "SIGABRT",
362 SIGBUS => "SIGBUS",
363 SIGFPE => "SIGFPE",
364 SIGKILL => "SIGKILL",
365 SIGUSR1 => "SIGUSR1",
366 SIGSEGV => "SIGSEGV",
367 SIGUSR2 => "SIGUSR2",
368 SIGPIPE => "SIGPIPE",
369 SIGALRM => "SIGALRM",
370 SIGTERM => "SIGTERM",
371 #[cfg(all(
372 any(target_os = "android", target_os = "emscripten", target_os = "linux"),
373 not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))
374 ))]
375 SIGSTKFLT => "SIGSTKFLT",
376 SIGCHLD => "SIGCHLD",
377 SIGCONT => "SIGCONT",
378 SIGSTOP => "SIGSTOP",
379 SIGTSTP => "SIGTSTP",
380 SIGTTIN => "SIGTTIN",
381 SIGTTOU => "SIGTTOU",
382 SIGURG => "SIGURG",
383 SIGXCPU => "SIGXCPU",
384 SIGXFSZ => "SIGXFSZ",
385 SIGVTALRM => "SIGVTALRM",
386 SIGPROF => "SIGPROF",
387 SIGWINCH => "SIGWINCH",
388 SIGIO => "SIGIO",
389 #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux"))]
390 SIGPWR => "SIGPWR",
391 SIGSYS => "SIGSYS",
392 #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
393 SIGEMT => "SIGEMT",
394 #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
395 SIGINFO => "SIGINFO",
396 }
397 }
398}
399
400impl AsRef<str> for Signal {
401 fn as_ref(&self) -> &str {
402 self.as_str()
403 }
404}
405
406/* We can now print the Signal */
407impl std::fmt::Display for Signal {
408 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
409 f.write_str(self.as_ref())
410 }
411}
412
413/* Array of Signal, platform dependent */
414#[cfg(all(
415 any(target_os = "linux", target_os = "android", target_os = "emscripten"),
416 not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))
417))]
418const SIGNALS: [Signal; 31] = [
419 SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL, SIGUSR1, SIGSEGV,
420 SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGSTKFLT, SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP, SIGTTIN,
421 SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH, SIGIO, SIGPWR, SIGSYS,
422];
423
424#[cfg(all(
425 any(target_os = "linux", target_os = "android", target_os = "emscripten"),
426 any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64")
427))]
428const SIGNALS: [Signal; 30] = [
429 SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL, SIGUSR1, SIGSEGV,
430 SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU,
431 SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH, SIGIO, SIGPWR, SIGSYS,
432];
433
434#[cfg(not(any(target_os = "linux", target_os = "android", target_os = "emscripten")))]
435const SIGNALS: [Signal; 31] = [
436 SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL, SIGUSR1, SIGSEGV,
437 SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU,
438 SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH, SIGIO, SIGSYS, SIGEMT, SIGINFO,
439];
440
441/* Count of the above signal constants + 1. Used to create HashMaps.with_capacity()
442 * and with from libc::c_int for array bounds checking.
443*/
444const NUM_SIGNALS: libc::c_int = 32;
445
446/*******************
447 * SIGNAL ITERATOR *
448 *******************/
449
450/// Useful if you want to set every signal to "Ignore" or "Default."
451///
452/// # Example
453/// ```
454/// use addy::Signal;
455///
456/// fn main() -> Result<(), addy::Error> {
457/// /* Have each intterupt print itself */
458/// for signal in Signal::iterator() {
459/// addy::mediate(signal).register("reflexive", |signal| {
460/// println!("Signal: {}", signal);
461/// })?;
462/// }
463/// Ok(())
464/// }
465/// ```
466#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
467pub struct SignalIterator {
468 next: usize,
469}
470
471impl Iterator for SignalIterator {
472 type Item = Signal;
473
474 fn next(&mut self) -> Option<Signal> {
475 if self.next < SIGNALS.len() {
476 let next_signal = SIGNALS[self.next];
477 self.next += 1;
478 Some(next_signal)
479 } else {
480 None
481 }
482 }
483}
484
485impl Signal {
486 /// Returns an iterator over the different Signals
487 pub fn iterator() -> SignalIterator {
488 SignalIterator { next: 0 }
489 }
490}
491
492/******************
493 * C FFI CALLBACK *
494 ******************/
495
496/* This is the callback passed to the C FF sigaction(...) - it is called with
497 * three arguments. We only care about what signal was called so we free() the
498 * other two, grab a copy of Sender and message pass what signal was called to
499 * the Event Loop.
500*/
501type CVoid = *mut libc::c_void;
502fn c_handler(signal: Signal, _info: CVoid, _ucontext: CVoid) {
503 /* We're the only function that interacts with this global static copy of
504 * a sender to the Event Loop. We only read from this location, only one
505 * interrupt can be active at a time so this is SAFE.
506 */
507 let sender;
508 unsafe {
509 sender = SENDER.as_ref().unwrap().clone();
510 }
511
512 /* Drop the error since we can't return one from across the kernel
513 * boundary.
514 */
515 let _ = sender.send(Action::Call(signal));
516}
517
518/*****************
519 * SIGNAL HANDLE *
520 *****************/
521
522/// This is the struct returned from an addy::mediate(Signal) call. It allows
523/// the caller to add, remove, and clear callbacks to the provided interrupt
524/// handler. Adding closures prevents the default bevaior (if any).
525///
526/// You can also set the interrupt to the default behaviour, or to be ignored by
527/// the process. If you set a signal to be ignored or back to the defaults you
528/// can call .resume() to to have it handle your callbacks again.
529///
530/// Dropping it does _not_ stop the signal handler. You must call .release() to
531/// have Addy stop handling this interrupt and free the associated resources.
532/// Conversely, you don't have to keep a handle to this around once you've set
533/// it up.
534///
535/// If you register callbacks for an interrupt, you must call .enable() to have
536/// them run. If you call .release() on a SignalHandler you must call .enable()
537/// again (after re-registering new callbacks).
538///
539/// # Example
540/// ```
541/// use addy::{Signal, SIGWINCH};
542///
543/// fn my_func(signal: Signal) {
544/// /* Does a thing */
545/// }
546///
547/// fn main() -> Result<(), addy::Error> {
548/// addy::mediate(SIGWINCH)
549/// .register("print", |_signal| { println!("Screen Resized!"); })?
550/// .register("my_func", my_func)?
551/// .enable()?;
552///
553/// //-- Later --//
554///
555/// // Ignore the incoming signal
556/// addy::mediate(SIGWINCH).ignore()?;
557///
558/// //-- Later Still --//
559///
560/// // Swap out one of the callbacks and re-enable capturing the interrupt
561/// addy::mediate(SIGWINCH)
562/// .remove("print")?
563/// .register("print", |_signal| { println!("New Output!"); })?
564/// .enable()?;
565///
566/// Ok(())
567/// }
568/// ```
569#[derive(Debug)]
570pub struct SignalHandle {
571 signal: Signal,
572 sender: Sender<Action>,
573}
574
575/* Convenient Type Alias */
576type SignalResult<'a> = Result<&'a mut SignalHandle, Error>;
577
578impl SignalHandle {
579 /// Registers a callback with the interrupt handler for the associated
580 /// Signal. If you call register with the same name it will replace the
581 /// previous callback.
582 ///
583 /// # Example
584 /// ```
585 /// use addy::{Signal, SIGWINCH};
586 ///
587 /// fn my_func(signal: Signal) {
588 /// /* Does a thing */
589 /// }
590 ///
591 /// fn main() -> Result<(), addy::Error> {
592 /// addy::mediate(SIGWINCH)
593 /// .register("print", |_signal| { println!("Screen Resized!"); })?
594 /// .register("my_func", my_func)?
595 /// .enable()?;
596 ///
597 /// Ok(())
598 /// }
599 /// ```
600 pub fn register<'a, A, F>(&'a mut self, name: A, cb: F) -> SignalResult
601 where
602 A: AsRef<str>,
603 F: Fn(Signal) -> () + Send + 'static,
604 {
605 /* Box the Callback */
606 let cb = CBP(Box::new(cb));
607 let name = String::from(name.as_ref());
608 self.sender
609 .send(Action::Register(self.signal, name, cb))
610 .map_err(|_| Error::CallFailed)?;
611 Ok(self)
612 }
613
614 /// Removes a named callback from the associated Signal. If no callback with
615 /// that name exists, it does nothing.
616 ///
617 /// # Example
618 /// ```
619 /// use addy::{Signal, SIGWINCH};
620 ///
621 /// fn my_func(signal: Signal) {
622 /// /* Does a thing */
623 /// }
624 ///
625 /// fn main() -> Result<(), addy::Error> {
626 /// addy::mediate(SIGWINCH)
627 /// .register("print", |_signal| { println!("Screen Resized!"); })?
628 /// .register("my_func", my_func)?
629 /// .enable()?;
630 ///
631 /// //-- Later --//
632 ///
633 /// // Stop calling "print" when the process receives a SIGWINCH signal
634 /// addy::mediate(SIGWINCH).remove("print")?;
635 ///
636 /// Ok(())
637 /// }
638 /// ```
639 pub fn remove<'a, A>(&'a mut self, name: A) -> SignalResult
640 where
641 A: AsRef<str>,
642 {
643 let name = String::from(name.as_ref());
644 self.sender
645 .send(Action::Remove(self.signal, name))
646 .map_err(|_| Error::CallFailed)?;
647 Ok(self)
648 }
649
650 /// Removes a all callbacks from the associated Signal. Functionally similar
651 /// to calling .ignore() except you don't need to call .enable() if you add
652 /// new callbacks later.
653 ///
654 /// # Example
655 /// ```
656 /// use addy::{Signal, SIGWINCH};
657 ///
658 /// fn my_func(signal: Signal) {
659 /// /* Does a thing */
660 /// }
661 ///
662 /// fn main() -> Result<(), addy::Error> {
663 /// addy::mediate(SIGWINCH)
664 /// .register("print", |_signal| { println!("Screen Resized!"); })?
665 /// .register("my_func", my_func)?
666 /// .enable()?;
667 ///
668 /// //-- Later --//
669 ///
670 /// // Capture the signal, but stop calling anything
671 /// addy::mediate(SIGWINCH)
672 /// .clear()?
673 /// .register("solo_callback", |_signal| { println!("ALONE!"); })?;
674 ///
675 /// Ok(())
676 /// }
677 /// ```
678 pub fn clear<'a>(&'a mut self) -> SignalResult {
679 self.sender
680 .send(Action::Clear(self.signal))
681 .map_err(|_| Error::CallFailed)?;
682 Ok(self)
683 }
684
685 /// Removes a all callbacks from the associated Signal and resets the
686 /// interrupt handler to the default behavior. Funcationally the same as
687 /// calling .clear() and .default().
688 ///
689 /// You will need to call .enable() again after re-registering callbacks.
690 ///
691 /// # Example
692 /// ```
693 /// use addy::SIGWINCH;
694 ///
695 /// fn main() -> Result<(), addy::Error> {
696 /// addy::mediate(SIGWINCH)
697 /// .register("print", |_signal| { println!("Screen Resized!"); })?
698 /// .enable()?;
699 ///
700 /// //-- Later --//
701 ///
702 /// // Stop capturing the signal
703 /// addy::mediate(SIGWINCH).release()?;
704 ///
705 /// //-- Later Still --//
706 ///
707 /// // Start catpuring again
708 /// addy::mediate(SIGWINCH)
709 /// .register("new", |_signal| { println!("New callback!"); })?
710 /// .enable()?;
711 ///
712 /// Ok(())
713 /// }
714 /// ```
715 pub fn release<'a>(&'a mut self) -> SignalResult {
716 self.sender
717 .send(Action::Release(self.signal))
718 .map_err(|_| Error::CallFailed)?;
719 Ok(self)
720 }
721
722 /// Tells the process to ignore this interrupt. Keeps all your callbacks.
723 /// Calling .resume() will re-enable them.
724 ///
725 /// # Example
726 /// ```
727 /// use addy::SIGWINCH;
728 ///
729 /// fn main() -> Result<(), addy::Error> {
730 /// addy::mediate(SIGWINCH)
731 /// .register("print", |_signal| { println!("Screen Resized!"); })?
732 /// .enable()?;
733 ///
734 /// //-- Later --//
735 ///
736 /// // Ignore the signal
737 /// addy::mediate(SIGWINCH).ignore()?;
738 ///
739 /// //-- Later Still --//
740 ///
741 /// // Start catpuring again
742 /// addy::mediate(SIGWINCH).resume()?;
743 ///
744 /// Ok(())
745 /// }
746 /// ```
747 pub fn ignore<'a>(&'a mut self) -> SignalResult {
748 self.sender
749 .send(Action::Ignore(self.signal))
750 .map_err(|_| Error::CallFailed)?;
751 Ok(self)
752 }
753
754 /// Restore the interrupt handler to the system default. Not all interrupts
755 /// have a default, and some interrupts default is to be ignored. Keeps all
756 /// your callbacks. Calling .resume() will re-enable them.
757 ///
758 /// # Example
759 /// ```
760 /// use addy::SIGINT;
761 ///
762 /// fn main() -> Result<(), addy::Error> {
763 /// addy::mediate(SIGINT)
764 /// .register("print", |_signal| { println!("Interrupted!"); })?
765 /// .enable()?;
766 ///
767 /// //-- Later --//
768 ///
769 /// // Set the signal to its default
770 /// addy::mediate(SIGINT).default()?;
771 ///
772 /// //-- Later Still --//
773 ///
774 /// // Start catpuring again
775 /// addy::mediate(SIGINT).resume()?;
776 ///
777 /// Ok(())
778 /// }
779 /// ```
780 pub fn default<'a>(&'a mut self) -> SignalResult {
781 self.sender
782 .send(Action::Default(self.signal))
783 .map_err(|_| Error::CallFailed)?;
784 Ok(self)
785 }
786
787 /// Resumes capturing the interrupt and calling any associated callbacks.
788 /// Most often used after a call to .ignore() and .default().
789 ///
790 /// Alias of .enable()
791 ///
792 /// # Example
793 /// ```
794 /// use addy::SIGINT;
795 ///
796 /// fn main() -> Result<(), addy::Error> {
797 /// addy::mediate(SIGINT)
798 /// .register("print", |_signal| { println!("Interrupted!"); })?
799 /// .enable()?;
800 ///
801 /// //-- Later --//
802 ///
803 /// // Set the signal to its default
804 /// addy::mediate(SIGINT).default()?;
805 ///
806 /// //-- Later Still --//
807 ///
808 /// // Start catpuring and printing "Interrupted!" again
809 /// addy::mediate(SIGINT).resume()?;
810 ///
811 /// Ok(())
812 /// }
813 /// ```
814 pub fn resume<'a>(&'a mut self) -> SignalResult {
815 self.sender
816 .send(Action::Resume(self.signal))
817 .map_err(|_| Error::CallFailed)?;
818 Ok(self)
819 }
820
821 /// Begins capturing the interrupt and calling any associated callbacks.
822 /// Most often used after a calls .register()
823 ///
824 /// Alias of .resume()
825 ///
826 /// # Example
827 /// ```
828 /// use addy::SIGINT;
829 ///
830 /// fn main() -> Result<(), addy::Error> {
831 /// addy::mediate(SIGINT)
832 /// .register("print", |_signal| { println!("Interrupted!"); })?
833 /// .enable()?;
834 /// Ok(())
835 /// }
836 /// ```
837 pub fn enable<'a>(&'a mut self) -> SignalResult {
838 self.sender
839 .send(Action::Resume(self.signal))
840 .map_err(|_| Error::CallFailed)?;
841 Ok(self)
842 }
843}
844
845/**************************************
846 * SETUP EVENT LOOP & MPSC CHANNEL *
847 **************************************/
848/* This is the thread that the different interrupt handlers send messages to.
849 * when they occur. They message what they want done and this thread executes it.
850*/
851
852/* This closure can only be called at most ONCE - allows us to ensure the Event
853 * Loop is set up a maximum of one time. This also means that if the MPSC
854 * channel ever fails we can't recover from it.
855*/
856static SETUP: Once = Once::new();
857
858/* FUTURE: Consider removing this to remove the dependency on lazy_static!()
859 * This gets set up ONCE and then only read from. The downside is more
860 * unsafe {} blocks :<
861 *
862 * Currently SENDER is only accessed in one place, that can only be run one at
863 * a time (i.e. in an interrupt) and copies of SAFE_SENDER can be made from
864 * any thread at any time. Still... it's read only...
865*/
866lazy_static! {
867 /* MPSC channel used by interrupts to communicate to the Event Loop. This
868 * stores a global copy of a Sender that can be cloned and given to the
869 * various interrupt handlers as they are created.
870 */
871 static ref SAFE_SENDER: Mutex<Option<Sender<Action>>> = {
872 Mutex::new(None)
873 };
874}
875
876/* C FFI MESSAGE PASSER
877 *
878 * Copy of a sender to the Event Loop. It is only setup ONCE on the first
879 * addy::mediate() call. The setup always occurs before it is READ from as it is
880 * set before any handler is registered (the only place that attempts to read
881 * from this static global).
882*/
883static mut SENDER: Option<Sender<Action>> = None;
884
885/* This is the initial Addy setup. It sets up the Event Loop and the MPCS
886 * channel. Setup occurs on the first call of addy::mediate(Signal).
887*/
888
889type NameToCallback = FnvHashMap<String, CBP>;
890type SignalToCallbacks<T> = FnvHashMap<Signal, T>;
891fn setup() {
892 /* Only setup the Event Loop once */
893 SETUP.call_once(|| {
894 // we may need to block on "completed" to make sure this is completed
895 // Setup an async MPSC channel - the receiver will be the Event Loop
896 let (sender, receiver) = mpsc::channel::<Action>();
897
898 /* Save a copy of a sender to a global variable so it can be
899 * clone()'d and handed off to future singal handlers structs.
900 */
901 {
902 let mut guard = SAFE_SENDER.lock().unwrap();
903 guard.replace(sender.clone());
904 }
905
906 /* Save a copy of the sender in an global static mut Option
907 *
908 * This is SAFE because this is only called ONCE and the only other
909 * place this is accessed is in fn c_handler() which cannot be called
910 * before this setup is run. In addition, only one interrupt handler can
911 * be running at a time, which is why this convolution is necessary.
912 */
913 unsafe {
914 SENDER.replace(sender.clone());
915 }
916
917 /**************
918 * EVENT LOOP *
919 **************/
920
921 /* Spawn the Event Loop thread, pass the receiver to it. */
922 thread::spawn(move || {
923 /* Create a map from Signal -> Map<Name, Closure> */
924 let nsig = usize::try_from(NUM_SIGNALS).unwrap(); // i32(32) - constant we control :)
925 let mut handlers = SignalToCallbacks::<NameToCallback>::with_capacity_and_hasher(
926 nsig,
927 Default::default(),
928 );
929
930 /* Stores if we need to re-establish fn c_handler() as the interrupt
931 * handler. e.g. if the user called .ignore() and then .resume()
932 */
933 let mut active: [bool; NUM_SIGNALS as usize] = [false; 32];
934
935 /*************
936 * CONSTANTS *
937 *************/
938 /* SigAction Structs to represent the SIG_DFL, SIG_IGN and custom
939 * handler. These are passed to libc::sigaction(...) to tell it what
940 * to do when a signal is called. They tell it to perform the
941 * default action, ignore the signal or run the list of user
942 * registered callbacks respectively.
943 */
944
945 /* Have to create a mask for the structs that enables all singals */
946 let mut sigset = std::mem::MaybeUninit::uninit();
947 let _ = unsafe { libc::sigfillset(sigset.as_mut_ptr()) };
948 let sigset = unsafe { sigset.assume_init() };
949
950 #[allow(non_snake_case)]
951 let SA_DEFAULT: libc::sigaction = libc::sigaction {
952 sa_sigaction: libc::SIG_DFL,
953 sa_mask: sigset,
954 sa_flags: libc::SA_SIGINFO,
955 #[cfg(target_os = "linux")]
956 sa_restorer: None,
957 };
958
959 #[allow(non_snake_case)]
960 let SA_IGNORE: libc::sigaction = libc::sigaction {
961 sa_sigaction: libc::SIG_IGN,
962 sa_mask: sigset,
963 sa_flags: libc::SA_SIGINFO,
964 #[cfg(target_os = "linux")]
965 sa_restorer: None,
966 };
967
968 /* Q: Why isn't this a constant?
969 * A: Converting function pointers to integers in a constant is
970 * unstable. (Yes I tried the various workarounds)
971 *
972 * Link: https://github.com/rust-lang/rust/issues/51910
973 */
974 #[allow(non_snake_case)]
975 let SA_CALLBACK: libc::sigaction = libc::sigaction {
976 sa_sigaction: c_handler as libc::sighandler_t,
977 sa_mask: sigset,
978 sa_flags: libc::SA_SIGINFO,
979 #[cfg(target_os = "linux")]
980 sa_restorer: None,
981 };
982
983 /***************************************
984 * HELPER FUNCTIONS TO KEEP THINGS DRY *
985 ***************************************/
986 /* Switched to helper closures because some architectures need
987 * a proper sa_mask generated to compile.
988 */
989
990 /* Tells the process to ignore the interrupt */
991 let ignore = move |signal: Signal| unsafe {
992 libc::sigaction(signal as libc::c_int, &SA_IGNORE, std::ptr::null_mut());
993 };
994 /* Sets the interrupt handler to the default value */
995 let default = move |signal: Signal| unsafe {
996 libc::sigaction(signal as libc::c_int, &SA_DEFAULT, std::ptr::null_mut());
997 };
998 /* Trys to convert a Signal to a USize to index into active[] */
999 fn index(signal: Signal) -> usize {
1000 usize::try_from(signal as libc::c_int).unwrap()
1001 }
1002 /* Resets all signals to their default behaviour. Does not clear out
1003 * registered handlers.
1004 */
1005 let set_all_to_default = || {
1006 for signal in Signal::iterator() {
1007 default(signal);
1008 }
1009 };
1010
1011 /*********
1012 * PANIC *
1013 *********/
1014
1015 /* If this thread panics for any reason, set all signals to the
1016 * default behavior.
1017 */
1018 let _ = std::panic::catch_unwind(|| {
1019 set_all_to_default();
1020 });
1021
1022 /**************
1023 * EVENT LOOP *
1024 **************/
1025
1026 /* Returns None when the channel is closed. */
1027 let mut messages = receiver.iter();
1028 while let Some(action) = messages.next() {
1029 match action {
1030 Action::Call(signal) => {
1031 /* Get the map of callbacks for this signal */
1032 if let Some(callbacks) = handlers.get(&signal) {
1033 /* Call each callback */
1034 let callbacks = callbacks.iter();
1035 for (_, cb) in callbacks {
1036 cb.0(signal);
1037 }
1038 }
1039 }
1040 Action::Register(signal, name, cb) => {
1041 /* Get the map of callbacks for this signal */
1042 let callbacks = handlers.entry(signal).or_default();
1043 callbacks.insert(name, cb);
1044 }
1045 Action::Remove(signal, name) => {
1046 /* Get the map of callbacks for this signal */
1047 if let Some(callbacks) = handlers.get_mut(&signal) {
1048 callbacks.remove(&name);
1049 }
1050 }
1051 Action::Clear(signal) => {
1052 handlers.remove(&signal);
1053 }
1054 Action::Ignore(signal) => {
1055 ignore(signal);
1056 active[index(signal)] = false;
1057 }
1058 Action::Default(signal) => {
1059 default(signal);
1060 active[index(signal)] = false;
1061 }
1062 Action::Release(signal) => {
1063 /* Clear the callback map */
1064 handlers.remove(&signal);
1065
1066 /* Set the handler back to the defaults */
1067 default(signal);
1068 active[index(signal)] = false;
1069 }
1070 Action::Resume(signal) => {
1071 /* Check to see if it's already setup up */
1072 if !active[index(signal)] {
1073 unsafe {
1074 /* SA_CALLBACK is a static sigaction struct that
1075 * points to c_handler(...)
1076 */
1077 libc::sigaction(
1078 signal as libc::c_int,
1079 &SA_CALLBACK,
1080 std::ptr::null_mut(),
1081 );
1082 }
1083 active[index(signal)] = true;
1084 }
1085 }
1086 }
1087 } // </Event Loop>
1088
1089 /* If the thread closes - set all the singals back to their default
1090 * behavior and remove all callbacks.
1091 */
1092 set_all_to_default();
1093 }); // </Thread>
1094 }); // </Once>
1095
1096 /* There's a chance that the ONCE call actually initialized something else
1097 * and that we're not ready so we spin until we are. Probably not necessary.
1098 *
1099 * Apparently it's only available on nightly, but is merged in and will be
1100 * stable shortly. See link below for detail:
1101 *
1102 * Link: https://github.com/rust-lang/rust/issues/54890
1103 */
1104 #[cfg(feature = "nightly")]
1105 while !SETUP.is_completed() { /*-- ᓚᘏᗢ --*/ }
1106}
1107
1108/***********
1109 * MEDIATE *
1110 ***********/
1111
1112/* If this is the FIRST time new has been called, for _any_ Signal it
1113 * will set up the Event Loop thread and MPCS handlers as well.
1114*/
1115/// Use this to get a SignalHandle representing a interrupt specified by Signal.
1116///
1117/// # Example
1118/// ```no_run
1119/// use addy::SIGWINCH;
1120/// use std::io::{Read, stdin};
1121///
1122/// fn main() -> Result<(), addy::Error> {
1123/// /* SIGWINCH is a POSIX interrupt signal */
1124/// addy::mediate(SIGWINCH)
1125/// .register("resized", |_signal| { println!("Screen Resized!"); })?
1126/// .enable()?;
1127///
1128/// /* Block so the program doesn't exit immediately
1129/// * Try resizing your terminal window :)
1130/// */
1131/// let mut buffer = [0; 1];
1132/// loop {
1133/// stdin().read(&mut buffer);
1134/// }
1135///
1136/// Ok(())
1137/// }
1138/// ```
1139pub fn mediate<S: Into<Signal>>(signal: S) -> SignalHandle {
1140 let signal = signal.into();
1141
1142 /* Performs the initial setup for all handlers - only called ONCE */
1143 setup();
1144
1145 /* Create a clone() of the Sender so we can pass messages to the Event
1146 * Loop from the returned struct.
1147 */
1148 let sender;
1149 {
1150 let guard = SAFE_SENDER.lock().unwrap();
1151 sender = guard.as_ref().unwrap().clone();
1152 }
1153
1154 SignalHandle { signal, sender }
1155}
1156
1157/* Alternative, arcane, profane function aliases for addy::mediate(...) */
1158#[doc(hidden)]
1159pub fn medicate(signal: Signal) {
1160 mediate(signal);
1161}
1162#[doc(hidden)]
1163pub fn intercept(signal: Signal) {
1164 mediate(signal);
1165}