signal-hook-0.1.12/.gitignore010064000017500000627000000000301355534043400142140ustar0000000000000000/target **/*.rs.bk tags signal-hook-0.1.12/.travis.yml010064000017500000627000000017271356423300300143440ustar0000000000000000language: rust cache: cargo rust: - 1.26.0 - stable - beta - nightly os: - windows - linux - osx before_script: - | (travis_wait rustup component add rustfmt-preview || true) && (test "$TRAVIS_RUST_VERSION" == 1.26.0 || travis_wait rustup component add clippy-preview || true) script: - | export PATH="$PATH":~/.cargo/bin && export RUST_BACKTRACE=1 && export CARGO_INCREMENTAL=1 && (test "$TRAVIS_RUST_VERSION" == 1.26.0 || rm -f Cargo.lock) && cargo build --all && cargo build --all --all-features && (test "$TRAVIS_RUST_VERSION" == 1.26.0 || cargo test --all) && (test "$TRAVIS_RUST_VERSION" == 1.26.0 || cargo test --all --all-features) && cargo doc --no-deps && (test "$TRAVIS_RUST_VERSION" == 1.26.0 || cargo clippy --all --tests -- --deny clippy::all) && (test "$TRAVIS_RUST_VERSION" == 1.26.0 || cargo fmt) matrix: allow_failures: - rust: nightly signal-hook-0.1.12/CHANGELOG.md010064000017500000627000000031341356625310200140420ustar0000000000000000# 0.1.12 * `cleanup` module to register resetting signals to default. # registry-1.2.0 * `unregister_signal`, to remove all hooks of one signal. # 0.1.11 * Docs improvements. * Fix registering pipes as well as sockets into the pipe module (#27). # registry-1.1.1 * Update deps. # registry-1.1.0 * Adding Windows support (thanks to @qnighy). # 0.1.10 * Fix busy loop in Iterator::forever when the mio-support feature is enabled (#16). # registry-1.0.1 * Include the registry files in the crates.io tarball. # 0.1.9 # registry-1.0.0 * Split into backend signal-hook-registry and the frontend. The backend is much less likely to have breaking changes so it contains the things that can be in the application just once. # 0.1.8 * The `Signals` iterator can now be closed (from another instance or thread), which can be used to shut down the thread handling signals from the main thread. # 0.1.7 * The `Signals` iterator allows adding signals after creation. * Fixed a bug where `Signals` registrations could be unregirestered too soon if the `Signals` was cloned previously. # 0.1.6 * The internally used ArcSwap thing doesn't block other ArcSwaps now (has independent generation lock). # 0.1.5 * Re-exported signal constants, so users no longer need libc. # 0.1.4 * Compilation fix for android-aarch64 # 0.1.3 * Tokio support. * Mio support. * Dependency updates. # 0.1.2 * Dependency updates. # 0.1.1 * Get rid of `catch_unwind` inside the signal handler. * Link to the nix crate. # 0.1.0 * Initial basic implementation. * Flag helpers. * Pipe helpers. * High-level iterator helper. signal-hook-0.1.12/Cargo.toml.orig010064000017500000627000000016701356625322200151260ustar0000000000000000[package] name = "signal-hook" version = "0.1.12" authors = ["Michal 'vorner' Vaner "] description = "Unix signal handling" documentation = "https://docs.rs/signal-hook" repository = "https://github.com/vorner/signal-hook" readme = "README.md" keywords = ["signal", "unix", "daemon"] license = "Apache-2.0/MIT" [badges] travis-ci = { repository = "vorner/signal-hook" } maintenance = { status = "actively-developed" } [features] mio-support = ["mio"] tokio-support = ["futures", "mio-support", "tokio-reactor"] [workspace] members = [ "./", "signal-hook-registry", ] [dependencies] libc = "~0.2" futures = { version = "~0.1", optional = true } mio = { version = "~0.6", optional = true } signal-hook-registry = { version = "~1.2", path = "signal-hook-registry" } tokio-reactor = { version = "~0.1", optional = true } [dev-dependencies] version-sync = "~0.8" tokio = "~0.1" [package.metadata.docs.rs] all-features = true signal-hook-0.1.12/Cargo.toml0000644000000026601356626316300114430ustar00# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] name = "signal-hook" version = "0.1.12" authors = ["Michal 'vorner' Vaner "] description = "Unix signal handling" documentation = "https://docs.rs/signal-hook" readme = "README.md" keywords = ["signal", "unix", "daemon"] license = "Apache-2.0/MIT" repository = "https://github.com/vorner/signal-hook" [package.metadata.docs.rs] all-features = true [dependencies.futures] version = "~0.1" optional = true [dependencies.libc] version = "~0.2" [dependencies.mio] version = "~0.6" optional = true [dependencies.signal-hook-registry] version = "~1.2" [dependencies.tokio-reactor] version = "~0.1" optional = true [dev-dependencies.tokio] version = "~0.1" [dev-dependencies.version-sync] version = "~0.8" [features] mio-support = ["mio"] tokio-support = ["futures", "mio-support", "tokio-reactor"] [badges.maintenance] status = "actively-developed" [badges.travis-ci] repository = "vorner/signal-hook" signal-hook-0.1.12/LICENSE-APACHE010064000017500000627000000251371331364546300141710ustar0000000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. signal-hook-0.1.12/LICENSE-MIT010064000017500000627000000020541331364546300136720ustar0000000000000000Copyright (c) 2017 tokio-jsonrpc developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. signal-hook-0.1.12/README.md010064000017500000627000000040111331364546300135100ustar0000000000000000# Signal-hook [![Travis Build Status](https://api.travis-ci.org/vorner/signal-hook.svg?branch=master)](https://travis-ci.org/vorner/signal-hook) Library for safe and correct Unix signal handling in Rust. Unix signals are inherently hard to handle correctly, for several reasons: * They are a global resource. If a library wants to set its own signal handlers, it risks disturbing some other library. It is possible to chain the previous signal handler, but then it is impossible to remove the old signal handlers from the chains in any practical manner. * They can be called from whatever thread, requiring synchronization. Also, as they can interrupt a thread at any time, making most handling race-prone. * According to the POSIX standard, the set of functions one may call inside a signal handler is limited to very few of them. To highlight, mutexes (or other locking mechanisms) and memory allocation and deallocation are *not* allowed. This library aims to solve some of the problems. It provides a global registry of actions performed on arrival of signals. It is possible to register multiple actions for the same signal and it is possible to remove the actions later on. If there was a previous signal handler when the first action for a signal is registered, it is chained (but the original one can't be removed). Besides the basic registration of an arbitrary action, several helper actions are provided to cover the needs of the most common use cases. For further details, see the [documentation](https://docs.rs/signal-hook). ## License Licensed under either of * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) at your option. ### Contribution Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. signal-hook-0.1.12/rustfmt.toml010064000017500000627000000000001331026567000146170ustar0000000000000000signal-hook-0.1.12/src/cleanup.rs010064000017500000627000000177711356625303400150350ustar0000000000000000//! Cleaning up signals. //! //! The routines in this module allow resetting the signals of an application back to defaults. //! This is intended for the following situation: //! //! * A terminal signal (eg. a `SIGTERM`, `SIGINT` or something similar) is received. //! * The application resets the signal handlers to defaults. //! * The application proceeds to perform some kind of shutdown (saving data, cleaning up, ...). //! * If another such signal is received, the application is terminated right away the hard way, //! without finishing the shutdown. //! //! The alternative of leaving the original signals in place might be problematic in case the //! shutdown takes a long time or when it gets stuck. In such case the application would appear to //! ignore the signal and just refuse to die. //! //! There are two ways to perform the reset: //! * Registering the reset as part of the signal handlers. This is more reliable (even in case the //! application is already stuck in some kind of infinite loop, it would still work). This is //! done by [register]. //! * Manually resetting the handlers just before the shutdown. This is done with [cleanup_signal]. use std::io::Error; #[cfg(not(windows))] use std::ptr; use libc::{c_int, sighandler_t, SIG_ERR}; #[cfg(not(windows))] use libc::SIG_DFL; // Unfortunately, not exported on windows :-(. Checked this actually works by tests/default.rs. #[cfg(windows)] const SIG_DFL: sighandler_t = 0; pub use signal_hook_registry::unregister_signal; use SigId; /// Resets the signal handler to the default one. /// /// This is the lowest level wrapper around resetting the signal handler to the OS default. It /// doesn't remove the hooks (though they will not get called), it doesn't handle errors and it /// doesn't return any previous chained signals. The hooks will simply stay registered but dormant. /// /// This function is async-signal-safe. However, you might prefer to use either [cleanup_signal] or /// [register]. /// /// # Warning /// /// This action is irreversible, once called, registering more hooks for the same signal will have /// no effect (neither the old nor the new ones will be active but the registration will appear to /// have succeeded). /// /// This behaviour **can change** in future versions without considering it a breaking change. /// /// In other words, this is expected to be called only before terminating the application and no /// further manipulation of the given signal is supported in any way. While it won't cause UB, it /// *will* produce unexpected results. pub fn cleanup_raw(signal: c_int) -> sighandler_t { unsafe { ::libc::signal(signal, SIG_DFL) } } /// Resets the signal handler to the default one and removes all its hooks. /// /// This resets the signal to the OS default. It doesn't revert to calling any previous signal /// handlers (the ones not handled by `signal-hook`). All the hooks registered for this signal are /// removed. /// /// The intended use case is making sure further instances of a terminal signal have immediate /// effect. If eg. a CTRL+C is pressed, the application removes all signal handling and proceeds to /// its own shutdown phase. If the shutdown phase takes too long or gets stuck, the user may press /// CTRL+C again which will then kill the application immediately, by a default signal action. /// /// # Warning /// /// This action is *global* (affecting hooks some other library or unrelated part of program /// registered) and *irreversible*. Once called, registering new hooks for this signal has no /// further effect (they'll appear to be registered, but they won't be called by the signal). The /// latter may change in the future and it won't be considered a breaking change. /// /// In other words, this is expected to be called only once the application enters its terminal /// state and is not supported otherwise. /// /// The function is **not** async-signal-safe. See [register] and [cleanup_raw] if you intend to /// reset the signal directly from inside the signal handler itself. /// /// # Examples /// /// ```rust /// # extern crate libc; /// # extern crate signal_hook; /// # /// # use std::io::Error; /// # use std::sync::atomic::{AtomicBool, Ordering}; /// # use std::sync::Arc; /// # /// # fn keep_processing() { std::thread::sleep(std::time::Duration::from_millis(50)); } /// # fn app_cleanup() {} /// use signal_hook::{cleanup, flag, SIGTERM}; /// /// fn main() -> Result<(), Error> { /// let terminated = Arc::new(AtomicBool::new(false)); /// flag::register(SIGTERM, Arc::clone(&terminated))?; /// # unsafe { libc::raise(SIGTERM) }; /// /// while !terminated.load(Ordering::Relaxed) { /// keep_processing(); /// } /// /// cleanup::cleanup_signal(SIGTERM)?; /// app_cleanup(); /// Ok(()) /// } /// ``` pub fn cleanup_signal(signal: c_int) -> Result<(), Error> { // We use `signal` both on unix and windows here. Unlike with regular functions, usage of // SIG_DFL is portable and much more convenient to use. let result = cleanup_raw(signal); // The cast is needed on windows :-|. if result == SIG_ERR as _ { return Err(Error::last_os_error()); } unregister_signal(signal); Ok(()) } #[cfg(not(windows))] fn verify_signals_exist(signals: &[c_int]) -> Result<(), Error> { signals .iter() .map(|s| -> Result<(), Error> { if unsafe { ::libc::sigaction(*s, ptr::null(), ptr::null_mut()) } == -1 { Err(Error::last_os_error()) } else { Ok(()) } }) .collect() } #[cfg(windows)] fn verify_signals_exist(_: &[c_int]) -> Result<(), Error> { // TODO: Do we have a way to check if the signals are valid on windows too? Ok(()) } /// Register a cleanup after receiving a signal. /// /// Registers an action that, after receiving `signal`, will reset all signals specified in /// `cleanup` to their OS defaults. The reset is done as part of the signal handler. /// /// The intended use case is that at CTRL+C (or something similar), the application starts shutting /// down. This might take some time so by resetting all terminal signals to the defaults at that /// time makes sure a second CTRL+C results in immediate (hard) termination of the application. /// /// The hooks are still left inside and any following hooks after the reset are still run. Only the /// next signal will be affected (and the hooks will be inert). /// /// # Warning /// /// The reset as part of the action is *global* and *irreversible*. All signal hooks and all /// signals registered outside of `signal-hook` are affected and won't be run any more. Registering /// more hooks for the same signals as cleaned will have no effect. /// /// The latter part of having no effect may be changed in the future, do not rely on it. /// Preferably, don't manipulate the signal any longer. /// /// # Examples /// /// ```rust /// # extern crate libc; /// # extern crate signal_hook; /// # /// # use std::io::Error; /// # use std::sync::atomic::{AtomicBool, Ordering}; /// # use std::sync::Arc; /// # /// # fn keep_processing() { std::thread::sleep(std::time::Duration::from_millis(50)); } /// # fn app_cleanup() {} /// use signal_hook::{cleanup, flag, SIGINT, SIGTERM}; /// /// fn main() -> Result<(), Error> { /// let terminated = Arc::new(AtomicBool::new(false)); /// flag::register(SIGTERM, Arc::clone(&terminated))?; /// cleanup::register(SIGTERM, vec![SIGTERM, SIGINT])?; /// # unsafe { libc::raise(SIGTERM) }; /// /// while !terminated.load(Ordering::Relaxed) { /// keep_processing(); /// } /// /// app_cleanup(); /// Ok(()) /// } /// ``` pub fn register(signal: c_int, cleanup: Vec) -> Result { verify_signals_exist(&cleanup)?; let hook = move || { for sig in &cleanup { // Note: we are ignoring the errors here. We have no way to handle them and the only // possible ones are invalid signals ‒ which we should have handled by // verify_signals_exist above. cleanup_raw(*sig); } }; unsafe { ::register(signal, hook) } } signal-hook-0.1.12/src/flag.rs010064000017500000627000000175131351701274400143060ustar0000000000000000//! Module for actions setting flags. //! //! This contains helper functions to set flags whenever a signal happens. The flags are atomic //! bools or numbers and the library manipulates them with the `SeqCst` ordering, in case someone //! cares about relative order to some *other* atomic variables. If you don't care about the //! relative order, you are free to use `Ordering::Relaxed` when reading and resetting the flags. //! //! # When to use //! //! The flags in this module allow for polling if a signal arrived since the previous poll. The do //! not allow blocking until something arrives. //! //! Therefore, the natural way to use them is in applications that have some kind of iterative work //! with both some upper and lower time limit on one iteration. If one iteration could block for //! arbitrary time, the handling of the signal would be postponed for a long time. If the iteration //! didn't block at all, the checking for the signal would turn into a busy-loop. //! //! If what you need is blocking until a signal comes, you might find better tools in the //! [`pipe`](../pipe/) and [`iterator`](../iterator/) modules. //! //! # Examples //! //! Doing something until terminated. This also knows by which signal it was terminated. In case //! multiple termination signals arrive before it is handled, it recognizes the last one. //! //! ```rust //! extern crate signal_hook; //! //! use std::io::Error; //! use std::sync::Arc; //! use std::sync::atomic::{AtomicUsize, Ordering}; //! //! use signal_hook::flag as signal_flag; //! //! fn main() -> Result<(), Error> { //! let term = Arc::new(AtomicUsize::new(0)); //! const SIGTERM: usize = signal_hook::SIGTERM as usize; //! const SIGINT: usize = signal_hook::SIGINT as usize; //! # #[cfg(not(windows))] //! const SIGQUIT: usize = signal_hook::SIGQUIT as usize; //! signal_flag::register_usize(signal_hook::SIGTERM, Arc::clone(&term), SIGTERM)?; //! signal_flag::register_usize(signal_hook::SIGINT, Arc::clone(&term), SIGINT)?; //! # #[cfg(not(windows))] //! signal_flag::register_usize(signal_hook::SIGQUIT, Arc::clone(&term), SIGQUIT)?; //! //! # // Hack to terminate the example when run as a doc-test. //! # term.store(SIGTERM, Ordering::Relaxed); //! loop { //! match term.load(Ordering::Relaxed) { //! 0 => { //! // Do some useful stuff here //! } //! SIGTERM => { //! eprintln!("Terminating on the TERM signal"); //! break; //! } //! SIGINT => { //! eprintln!("Terminating on the INT signal"); //! break; //! } //! # #[cfg(not(windows))] //! SIGQUIT => { //! eprintln!("Terminating on the QUIT signal"); //! break; //! } //! _ => unreachable!(), //! } //! } //! //! Ok(()) //! } //! ``` //! //! Sending a signal to self and seeing it arrived (not of a practical usage on itself): //! //! ```rust //! extern crate libc; //! extern crate signal_hook; //! //! use std::io::Error; //! use std::sync::Arc; //! use std::sync::atomic::{AtomicBool, Ordering}; //! use std::thread; //! use std::time::Duration; //! //! fn main() -> Result<(), Error> { //! let got = Arc::new(AtomicBool::new(false)); //! # #[cfg(not(windows))] //! signal_hook::flag::register(signal_hook::SIGUSR1, Arc::clone(&got))?; //! # #[cfg(windows)] //! # signal_hook::flag::register(signal_hook::SIGTERM, Arc::clone(&got))?; //! unsafe { //! # #[cfg(not(windows))] //! libc::raise(signal_hook::SIGUSR1); //! # #[cfg(windows)] //! # libc::raise(signal_hook::SIGTERM); //! } //! // A sleep here, because it could run the signal handler in another thread and we may not //! // see the flag right away. This is still a hack and not guaranteed to work, it is just an //! // example! //! thread::sleep(Duration::from_secs(1)); //! assert!(got.load(Ordering::Relaxed)); //! Ok(()) //! } //! ``` //! //! Reloading a configuration on `SIGHUP` (which is a common behaviour of many UNIX daemons, //! together with reopening the log file). //! //! ```rust //! extern crate signal_hook; //! //! use std::io::Error; //! use std::sync::Arc; //! use std::sync::atomic::{AtomicBool, Ordering}; //! //! use signal_hook::flag as signal_flag; //! //! fn main() -> Result<(), Error> { //! // We start with true, to load the configuration in the very first iteration too. //! let reload = Arc::new(AtomicBool::new(true)); //! let term = Arc::new(AtomicBool::new(false)); //! # #[cfg(not(windows))] //! signal_flag::register(signal_hook::SIGHUP, Arc::clone(&reload))?; //! signal_flag::register(signal_hook::SIGINT, Arc::clone(&term))?; //! signal_flag::register(signal_hook::SIGTERM, Arc::clone(&term))?; //! # #[cfg(not(windows))] //! signal_flag::register(signal_hook::SIGQUIT, Arc::clone(&term))?; //! while !term.load(Ordering::Relaxed) { //! // Using swap here, not load, to reset it back to false once it is reloaded. //! if reload.swap(false, Ordering::Relaxed) { //! // Reload the config here //! # //! # // Hiden hack to make the example terminate when run as doc-test. Not part of the //! # // real code. //! # term.store(true, Ordering::Relaxed); //! } //! // Serve one request //! } //! Ok(()) //! } //! ``` use std::io::Error; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use std::sync::Arc; use libc::c_int; use SigId; /// Registers an action to set the flag to `true` whenever the given signal arrives. pub fn register(signal: c_int, flag: Arc) -> Result { // We use SeqCst for two reasons: // * Signals should not come very often, so the performance does not really matter. // * We promise the order of actions, but setting different atomics with Relaxed or similar // would not guarantee the effective order. unsafe { ::register(signal, move || flag.store(true, Ordering::SeqCst)) } } /// Registers an action to set the flag to the given value whenever the signal arrives. pub fn register_usize(signal: c_int, flag: Arc, value: usize) -> Result { unsafe { ::register(signal, move || flag.store(value, Ordering::SeqCst)) } } #[cfg(test)] mod tests { use std::sync::atomic; use std::time::{Duration, Instant}; use libc; use super::*; fn self_signal() { unsafe { #[cfg(not(windows))] libc::raise(::SIGUSR1); #[cfg(windows)] libc::raise(::SIGTERM); } } fn wait_flag(flag: &AtomicBool) -> bool { let start = Instant::now(); while !flag.load(Ordering::Relaxed) { atomic::spin_loop_hint(); if Instant::now() - start > Duration::from_secs(1) { // We reached a timeout and nothing happened yet. // In theory, using timeouts for thread-synchronization tests is wrong, but a // second should be enough in practice. return false; } } true } #[test] fn register_unregister() { // When we register the action, it is active. let flag = Arc::new(AtomicBool::new(false)); #[cfg(not(windows))] let signal = register(::SIGUSR1, Arc::clone(&flag)).unwrap(); #[cfg(windows)] let signal = register(::SIGTERM, Arc::clone(&flag)).unwrap(); self_signal(); assert!(wait_flag(&flag)); // But stops working after it is unregistered. assert!(::unregister(signal)); flag.store(false, Ordering::Relaxed); self_signal(); assert!(!wait_flag(&flag)); // And the unregistration actually dropped its copy of the Arc assert_eq!(1, Arc::strong_count(&flag)); } } signal-hook-0.1.12/src/iterator.rs010064000017500000627000000506331356423300300152210ustar0000000000000000//! An iterator over incoming signals. //! //! This provides a higher abstraction over the signals, providing a structure //! ([`Signals`](struct.Signals.html)) able to iterate over the incoming signals. //! //! In case the `tokio-support` feature is turned on, the [`Async`](struct.Async.html) is also //! available, making it possible to integrate with the tokio runtime. //! //! # Examples //! //! ```rust //! extern crate libc; //! extern crate signal_hook; //! //! use std::io::Error; //! //! use signal_hook::iterator::Signals; //! //! fn main() -> Result<(), Error> { //! let signals = Signals::new(&[ //! signal_hook::SIGHUP, //! signal_hook::SIGTERM, //! signal_hook::SIGINT, //! signal_hook::SIGQUIT, //! # signal_hook::SIGUSR1, //! ])?; //! # // A trick to terminate the example when run as doc-test. Not part of the real code. //! # unsafe { libc::raise(signal_hook::SIGUSR1) }; //! 'outer: loop { //! // Pick up signals that arrived since last time //! for signal in signals.pending() { //! match signal as libc::c_int { //! signal_hook::SIGHUP => { //! // Reload configuration //! // Reopen the log file //! } //! signal_hook::SIGTERM | signal_hook::SIGINT | signal_hook::SIGQUIT => { //! break 'outer; //! }, //! # signal_hook::SIGUSR1 => return Ok(()), //! _ => unreachable!(), //! } //! } //! // Do some bit of work ‒ something with upper limit on waiting, so we don't block //! // forever with a SIGTERM already waiting. //! } //! println!("Terminating. Bye bye"); //! Ok(()) //! } //! ``` use std::borrow::Borrow; use std::io::Error; use std::iter::Enumerate; use std::os::unix::io::AsRawFd; use std::os::unix::net::UnixStream; use std::slice::Iter; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, Mutex}; use libc::{self, c_int}; use pipe; use SigId; /// Maximal signal number we support. const MAX_SIGNUM: usize = 128; #[derive(Debug)] struct Waker { pending: Vec, closed: AtomicBool, read: UnixStream, write: UnixStream, } impl Waker { /// Sends a wakeup signal to the internal wakeup pipe. fn wake(&self) { pipe::wake(self.write.as_raw_fd()); } } #[derive(Debug)] struct RegisteredSignals(Mutex>>); impl Drop for RegisteredSignals { fn drop(&mut self) { let lock = self.0.lock().unwrap(); for id in lock.iter().filter_map(|s| *s) { ::unregister(id); } } } /// The main structure of the module, representing interest in some signals. /// /// Unlike the helpers in other modules, this registers the signals when created and unregisters /// them on drop. It provides the pending signals during its lifetime, either in batches or as an /// infinite iterator. /// /// # Multiple consumers /// /// You may have noticed this structure can be used simultaneously by multiple threads. If it is /// done, a signal arrives to one of the threads (on the first come, first serve basis). The signal /// is *not* broadcasted to all currently active threads. /// /// A similar thing applies to cloning the structure ‒ at least one of the copies gets the signal, /// but it is not broadcasted to all of them. /// /// If you need multiple recipients, you can create multiple independent instances (not by cloning, /// but by the constructor). /// /// # Examples /// /// ```rust /// # extern crate signal_hook; /// # /// # use std::io::Error; /// # use std::thread; /// use signal_hook::iterator::Signals; /// /// # /// # fn main() -> Result<(), Error> { /// let signals = Signals::new(&[signal_hook::SIGUSR1, signal_hook::SIGUSR2])?; /// thread::spawn(move || { /// for signal in &signals { /// match signal { /// signal_hook::SIGUSR1 => {}, /// signal_hook::SIGUSR2 => {}, /// _ => unreachable!(), /// } /// } /// }); /// # Ok(()) /// # } /// ``` /// /// # `mio` support /// /// If the crate is compiled with the `mio-support` flag, the `Signals` becomes pluggable into /// `mio` (it implements the `Evented` trait). If it becomes readable, there may be new signals to /// pick up. The structure is expected to be registered with level triggered mode. /// /// # `tokio` support /// /// If the crate is compiled with the `tokio-support` flag, the [`into_async`](#method.into_async) /// method becomes available. This method turns the iterator into an asynchronous stream of /// received signals. #[derive(Clone, Debug)] pub struct Signals { ids: Arc, waker: Arc, } impl Signals { /// Creates the `Signals` structure. /// /// This registers all the signals listed. The same restrictions (panics, errors) apply as with /// [`register`](../fn.register.html). pub fn new(signals: I) -> Result where I: IntoIterator, S: Borrow, { let (read, write) = UnixStream::pair()?; let pending = (0..MAX_SIGNUM).map(|_| AtomicBool::new(false)).collect(); let waker = Arc::new(Waker { pending, closed: AtomicBool::new(false), read, write, }); let ids = (0..MAX_SIGNUM).map(|_| None).collect(); let me = Self { ids: Arc::new(RegisteredSignals(Mutex::new(ids))), waker, }; for sig in signals { me.add_signal(*sig.borrow())?; } Ok(me) } /// Registers another signal to the set watched by this [`Signals`] instance. /// /// # Notes /// /// * This is safe to call concurrently from whatever thread. /// * This is *not* safe to call from within a signal handler. /// * If the signal number was already registered previously, this is a no-op. /// * If this errors, the original set of signals is left intact. /// * This actually registers the signal into the whole group of [`Signals`] cloned from each /// other, so any of them might start receiving the signals. /// /// # Panics /// /// * If the given signal is [forbidden][::FORBIDDEN]. /// * If the signal number is negative or larger than internal limit. The limit should be /// larger than any supported signal the OS supports. pub fn add_signal(&self, signal: c_int) -> Result<(), Error> { assert!(signal >= 0); assert!( (signal as usize) < MAX_SIGNUM, "Signal number {} too large. If your OS really supports such signal, file a bug", signal, ); let mut lock = self.ids.0.lock().unwrap(); // Already registered, ignoring if lock[signal as usize].is_some() { return Ok(()); } let waker = Arc::clone(&self.waker); let action = move || { waker.pending[signal as usize].store(true, Ordering::SeqCst); waker.wake(); }; let id = unsafe { ::register(signal, action) }?; lock[signal as usize] = Some(id); Ok(()) } /// Reads data from the internal self-pipe. /// /// If `wait` is `true` and there are no data in the self pipe, it blocks until some come. /// /// Returns weather it successfully read something. fn flush(&self, wait: bool) -> bool { // Just an optimisation.. would work without it too. if self.waker.closed.load(Ordering::SeqCst) { return false; } const SIZE: usize = 1024; let mut buff = [0u8; SIZE]; let res = unsafe { // We ignore all errors on purpose. This should not be something like closed file // descriptor. It could EAGAIN, but that's OK in case we say MSG_DONTWAIT. If it's // EINTR, then it's OK too, it'll only create a spurious wakeup. libc::recv( self.waker.read.as_raw_fd(), buff.as_mut_ptr() as *mut libc::c_void, SIZE, if wait { 0 } else { libc::MSG_DONTWAIT }, ) }; if self.waker.closed.load(Ordering::SeqCst) { // Wake any other sleeping ends // (if none wait, it'll only leave garbage inside the pipe, but we'll close it soon // anyway). self.waker.wake(); } res > 0 } /// Returns an iterator of already received signals. /// /// This returns an iterator over all the signal numbers of the signals received since last /// time they were read (out of the set registered by this `Signals` instance). Note that they /// are returned in arbitrary order and a signal number is returned only once even if it was /// received multiple times. /// /// This method returns immediately (does not block) and may produce an empty iterator if there /// are no signals ready. pub fn pending(&self) -> Pending { self.flush(false); Pending(self.waker.pending.iter().enumerate()) } /// Waits for some signals to be available and returns an iterator. /// /// This is similar to [`pending`](#method.pending). If there are no signals available, it /// tries to wait for some to arrive. However, due to implementation details, this still can /// produce an empty iterator. /// /// This can block for arbitrary long time. /// /// Note that the blocking is done in this method, not in the iterator. pub fn wait(&self) -> Pending { self.flush(true); Pending(self.waker.pending.iter().enumerate()) } /// Returns an infinite iterator over arriving signals. /// /// The iterator's `next()` blocks as necessary to wait for signals to arrive. This is adequate /// if you want to designate a thread solely to handling signals. If multiple signals come at /// the same time (between two values produced by the iterator), they will be returned in /// arbitrary order. Multiple instances of the same signal may be collated. /// /// This is also the iterator returned by `IntoIterator` implementation on `&Signals`. /// /// This iterator terminates only if the [`Signals`] is explicitly [closed][Signals::close]. /// /// # Examples /// /// ```rust /// # extern crate libc; /// # extern crate signal_hook; /// # /// # use std::io::Error; /// # use std::thread; /// # /// use signal_hook::iterator::Signals; /// /// # fn main() -> Result<(), Error> { /// let signals = Signals::new(&[signal_hook::SIGUSR1, signal_hook::SIGUSR2])?; /// thread::spawn(move || { /// for signal in signals.forever() { /// match signal { /// signal_hook::SIGUSR1 => {}, /// signal_hook::SIGUSR2 => {}, /// _ => unreachable!(), /// } /// } /// }); /// # Ok(()) /// # } /// ``` pub fn forever(&self) -> Forever { Forever { signals: self, iter: self.pending(), } } /// Is it closed? /// /// See [`close`][Signals::close]. pub fn is_closed(&self) -> bool { self.waker.closed.load(Ordering::SeqCst) } /// Closes the instance. /// /// This is meant to signalize termination through all the interrelated instances ‒ the ones /// created by cloning the same original [`Signals`] instance (and all the [`Async`] ones /// created from them). After calling close: /// /// * [`is_closed`][Signals::is_closed] will return true. /// * All currently blocking operations on all threads and all the instances are interrupted /// and terminate. /// * Any further operations will never block. /// * Further signals may or may not be returned from the iterators. However, if any are /// returned, these are real signals that happened. /// * The [`forever`][Signals::forever] terminates (follows from the above). /// /// The goal is to be able to shut down any background thread that handles only the signals. /// /// ```rust /// # use signal_hook::iterator::Signals; /// # use signal_hook::SIGUSR1; /// # fn main() -> Result<(), std::io::Error> { /// let signals = Signals::new(&[SIGUSR1])?; /// let signals_bg = signals.clone(); /// let thread = std::thread::spawn(move || { /// for signal in &signals_bg { /// // Whatever with the signal /// # let _ = signal; /// } /// }); /// /// signals.close(); /// /// // The thread will terminate on its own now (the for cycle runs out of signals). /// thread.join().expect("background thread panicked"); /// # Ok(()) } /// ``` pub fn close(&self) { self.waker.closed.store(true, Ordering::SeqCst); self.waker.wake(); } } impl<'a> IntoIterator for &'a Signals { type Item = c_int; type IntoIter = Forever<'a>; fn into_iter(self) -> Forever<'a> { self.forever() } } /// The iterator of one batch of signals. /// /// This is returned by the [`pending`](struct.Signals.html#method.pending) and /// [`wait`](struct.Signals.html#method.wait) methods. pub struct Pending<'a>(Enumerate>); impl<'a> Iterator for Pending<'a> { type Item = c_int; fn next(&mut self) -> Option { while let Some((sig, flag)) = self.0.next() { if flag .compare_exchange(true, false, Ordering::SeqCst, Ordering::Relaxed) .is_ok() { return Some(sig as c_int); } } None } } /// The infinite iterator of signals. /// /// It is returned by the [`forever`](struct.Signals.html#method.forever) and by the `IntoIterator` /// implementation of [`&Signals`](struct.Signals.html). pub struct Forever<'a> { signals: &'a Signals, iter: Pending<'a>, } impl<'a> Iterator for Forever<'a> { type Item = c_int; fn next(&mut self) -> Option { while !self.signals.is_closed() { if let Some(result) = self.iter.next() { return Some(result); } self.iter = self.signals.wait(); } None } } #[cfg(feature = "mio-support")] mod mio_support { use std::io::Error; use std::os::unix::io::AsRawFd; use mio::event::Evented; use mio::unix::EventedFd; use mio::{Poll, PollOpt, Ready, Token}; use super::Signals; impl Evented for Signals { fn register( &self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt, ) -> Result<(), Error> { EventedFd(&self.waker.read.as_raw_fd()).register(poll, token, interest, opts) } fn reregister( &self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt, ) -> Result<(), Error> { EventedFd(&self.waker.read.as_raw_fd()).reregister(poll, token, interest, opts) } fn deregister(&self, poll: &Poll) -> Result<(), Error> { EventedFd(&self.waker.read.as_raw_fd()).deregister(poll) } } #[cfg(test)] mod tests { use std::time::Duration; use libc; use mio::Events; use super::*; #[test] fn mio_wakeup() { let signals = Signals::new(&[::SIGUSR1]).unwrap(); let token = Token(0); let poll = Poll::new().unwrap(); poll.register(&signals, token, Ready::readable(), PollOpt::level()) .unwrap(); let mut events = Events::with_capacity(10); unsafe { libc::raise(::SIGUSR1) }; poll.poll(&mut events, Some(Duration::from_secs(10))) .unwrap(); let event = events.iter().next().unwrap(); assert!(event.readiness().is_readable()); assert_eq!(token, event.token()); let sig = signals.pending().next().unwrap(); assert_eq!(::SIGUSR1, sig); } } } #[cfg(feature = "tokio-support")] mod tokio_support { use std::io::Error; use std::sync::atomic::Ordering; use futures::stream::Stream; use futures::{Async as AsyncResult, Poll}; use libc::{self, c_int}; use tokio_reactor::{Handle, Registration}; use super::Signals; /// An asynchronous stream of registered signals. /// /// It is created by converting [`Signals`](struct.Signals.html). See /// [`Signals::into_async`](struct.Signals.html#method.into_async). /// /// # Cloning /// /// If you register multiple signals, then create multiple `Signals` instances by cloning and /// convert them to `Async`, one of them can „steal“ wakeups for several signals at once. This /// one will produce the signals while the others will be silent. /// /// This has an effect if the one consumes them slowly or is dropped after the first one. /// /// It is recommended not to clone the `Signals` instances and keep just one `Async` stream /// around. #[derive(Debug)] pub struct Async { registration: Registration, inner: Signals, // It seems we can't easily use the iterator into the array here because of lifetimes ‒ // using non-'static things in around futures is real pain. position: usize, } impl Async { /// Creates a new `Async`. pub fn new(signals: Signals, handle: &Handle) -> Result { let registration = Registration::new(); registration.register_with(&signals, handle)?; Ok(Async { registration, inner: signals, position: 0, }) } } impl Stream for Async { type Item = libc::c_int; type Error = Error; fn poll(&mut self) -> Poll, Self::Error> { while !self.inner.is_closed() { if self.position >= self.inner.waker.pending.len() { if self.registration.poll_read_ready()?.is_not_ready() { return Ok(AsyncResult::NotReady); } // Non-blocking clean of the pipe while self.inner.flush(false) {} // By now we have an indication there might be some stuff inside the signals, // reset the scanning position self.position = 0; } assert!(self.position < self.inner.waker.pending.len()); let sig = &self.inner.waker.pending[self.position]; let sig_num = self.position; self.position += 1; if sig .compare_exchange(true, false, Ordering::SeqCst, Ordering::Relaxed) .is_ok() { // Successfully claimed a signal, return it return Ok(AsyncResult::Ready(Some(sig_num as c_int))); } } Ok(AsyncResult::Ready(None)) } } impl Signals { /// Turns the iterator into an asynchronous stream. /// /// This allows getting the signals in asynchronous way in a tokio event loop. Available /// only if compiled with the `tokio-support` feature enabled. /// /// # Examples /// /// ```rust /// extern crate libc; /// extern crate signal_hook; /// extern crate tokio; /// /// use std::io::Error; /// /// use signal_hook::iterator::Signals; /// use tokio::prelude::*; /// /// fn main() -> Result<(), Error> { /// let wait_signal = Signals::new(&[signal_hook::SIGUSR1])? /// .into_async()? /// .into_future() /// .map(|sig| assert_eq!(sig.0.unwrap(), signal_hook::SIGUSR1)) /// .map_err(|e| panic!("{}", e.0)); /// unsafe { libc::raise(signal_hook::SIGUSR1) }; /// tokio::run(wait_signal); /// Ok(()) /// } /// ``` pub fn into_async(self) -> Result { Async::new(self, &Handle::default()) } /// Turns the iterator into a stream, tied into a specific tokio reactor. pub fn into_async_with_handle(self, handle: &Handle) -> Result { Async::new(self, handle) } } } #[cfg(feature = "tokio-support")] pub use self::tokio_support::Async; signal-hook-0.1.12/src/lib.rs010064000017500000627000000200401356625312000141270ustar0000000000000000#![doc( html_root_url = "https://docs.rs/signal-hook/0.1.12/signal-hook/", test(attr(deny(warnings))), test(attr(allow(bare_trait_objects, unknown_lints))) )] #![deny(missing_docs, warnings)] // Don't fail on links to things not enabled in features #![allow(unknown_lints, intra_doc_link_resolution_failure)] //! Library for easier and safe Unix signal handling //! //! Unix signals are inherently hard to handle correctly, for several reasons: //! //! * They are a global resource. If a library wants to set its own signal handlers, it risks //! disturbing some other library. It is possible to chain the previous signal handler, but then //! it is impossible to remove the old signal handlers from the chains in any practical manner. //! * They can be called from whatever thread, requiring synchronization. Also, as they can //! interrupt a thread at any time, making most handling race-prone. //! * According to the POSIX standard, the set of functions one may call inside a signal handler is //! limited to very few of them. To highlight, mutexes (or other locking mechanisms) and memory //! allocation and deallocation is *not* allowed. //! //! This library aims to solve some of the problems. It provides a global registry of actions //! performed on arrival of signals. It is possible to register multiple actions for the same //! signal and it is possible to remove the actions later on. If there was a previous signal //! handler when the first action for a signal is registered, it is chained (but the original one //! can't be removed). //! //! The main function of the library is [`register`](fn.register.html). //! //! It also offers several common actions one might want to register, implemented in the correct //! way. They are scattered through submodules and have the same limitations and characteristics as //! the [`register`](fn.register.html) function. Generally, they work to postpone the action taken //! outside of the signal handler, where the full freedom and power of rust is available. //! //! Unlike other Rust libraries for signal handling, this should be flexible enough to handle all //! the common and useful patterns. //! //! The library avoids all the newer fancy signal-handling routines. These generally have two //! downsides: //! //! * They are not fully portable, therefore the library would have to contain *both* the //! implementation using the basic routines and the fancy ones. As signal handling is not on the //! hot path of most programs, this would not bring any actual benefit. //! * The other routines require that the given signal is masked in all application's threads. As //! the signals are not masked by default and a new thread inherits the signal mask of its //! parent, it is possible to guarantee such global mask by masking them before any threads //! start. While this is possible for an application developer to do, it is not possible for a //! a library. //! //! # Warning //! //! Even with this library, you should thread with care. It does not eliminate all the problems //! mentioned above. //! //! Also, note that the OS may collate multiple instances of the same signal into just one call of //! the signal handler. Furthermore, some abstractions implemented here also naturally collate //! multiple instances of the same signal. The general guarantee is, if there was at least one //! signal of the given number delivered, an action will be taken, but it is not specified how many //! times ‒ signals work mostly as kind of „wake up now“ nudge, if the application is slow to wake //! up, it may be nudged multiple times before it does so. //! //! # Signal limitations //! //! OS limits still apply ‒ it is not possible to redefine certain signals (eg. `SIGKILL` or //! `SIGSTOP`) and it is probably a *very* stupid idea to touch certain other ones (`SIGSEGV`, //! `SIGFPE`, `SIGILL`). Therefore, this library will panic if any attempt at manipulating these is //! made. There are some use cases for redefining the latter ones, but these are not well served by //! this library and you really *really* have to know what you're doing and are generally on your //! own doing that. //! //! # Signal masks //! //! As the library uses `sigaction` under the hood, signal masking works as expected (eg. with //! `pthread_sigmask`). This means, signals will *not* be delivered if the signal is masked in all //! program's threads. //! //! By the way, if you do want to modify the signal mask (or do other Unix-specific magic), the //! [nix](https://crates.io/crates/nix) crate offers safe interface to many low-level functions, //! including //! [`pthread_sigmask`](https://docs.rs/nix/0.11.0/nix/sys/signal/fn.pthread_sigmask.html). //! //! # Portability //! //! It should work on any POSIX.1-2001 system, which are all the major big OSes with the notable //! exception of Windows. //! //! This crate includes a limited support for Windows, based on `signal`/`raise` in the CRT. //! There are differences in both API and behavior: //! //! - `iterator` and `pipe` are not yet implemented. //! - We have only a few signals: `SIGABRT`, `SIGABRT_COMPAT`, `SIGBREAK`, //! `SIGFPE`, `SIGILL`, `SIGINT`, `SIGSEGV` and `SIGTERM`. //! - Due to lack of signal blocking, there's a race condition. //! After the call to `signal`, there's a moment where we miss a signal. //! That means when you register a handler, there may be a signal which invokes //! neither the default handler or the handler you register. //! - Handlers registered by `signal` in Windows are cleared on first signal. //! To match behavior in other platforms, we re-register the handler each time the handler is //! called, but there's a moment where we miss a handler. //! That means when you receive two signals in a row, there may be a signal which invokes //! the default handler, nevertheless you certainly have registered the handler. //! //! Moreover, signals won't work as you expected. `SIGTERM` isn't actually used and //! not all `Ctrl-C`s are turned into `SIGINT`. //! //! Patches to improve Windows support in this library are welcome. //! //! # Examples //! //! ```rust //! extern crate signal_hook; //! //! use std::io::Error; //! use std::sync::Arc; //! use std::sync::atomic::{AtomicBool, Ordering}; //! //! fn main() -> Result<(), Error> { //! let term = Arc::new(AtomicBool::new(false)); //! signal_hook::flag::register(signal_hook::SIGTERM, Arc::clone(&term))?; //! while !term.load(Ordering::Relaxed) { //! // Do some time-limited stuff here //! // (if this could block forever, then there's no guarantee the signal will have any //! // effect). //! # //! # // Hack to terminate the example, not part of the real code. //! # term.store(true, Ordering::Relaxed); //! } //! Ok(()) //! } //! ``` //! //! # Features //! //! * `mio-support`: The [`Signals` iterator](iterator/struct.Signals.html) becomes pluggable into //! mio. //! * `tokio-support`: The [`Signals`](iterator/struct.Signals.html) can be turned into //! [`Async`](iterator/struct.Async.html), which provides a `Stream` interface for integration in //! the asynchronous world. #[cfg(feature = "tokio-support")] extern crate futures; extern crate libc; #[cfg(feature = "mio-support")] extern crate mio; extern crate signal_hook_registry; #[cfg(feature = "tokio-support")] extern crate tokio_reactor; pub mod cleanup; pub mod flag; #[cfg(not(windows))] pub mod iterator; #[cfg(not(windows))] pub mod pipe; #[cfg(not(windows))] pub use libc::{ SIGABRT, SIGALRM, SIGBUS, SIGCHLD, SIGCONT, SIGFPE, SIGHUP, SIGILL, SIGINT, SIGIO, SIGKILL, SIGPIPE, SIGPROF, SIGQUIT, SIGSEGV, SIGSTOP, SIGSYS, SIGTERM, SIGTRAP, SIGUSR1, SIGUSR2, SIGWINCH, }; #[cfg(windows)] pub use libc::{SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV, SIGTERM}; // NOTE: they perhaps deserve backport to libc. #[cfg(windows)] /// Same as `SIGABRT`, but the number is compatible to other platforms. pub const SIGABRT_COMPAT: libc::c_int = 6; #[cfg(windows)] /// Ctrl-Break is pressed for Windows Console processes. pub const SIGBREAK: libc::c_int = 21; pub use signal_hook_registry::{register, unregister, SigId, FORBIDDEN}; signal-hook-0.1.12/src/pipe.rs010064000017500000627000000204001355760716600143330ustar0000000000000000//! Module with the self-pipe pattern. //! //! One of the common patterns around signals is to have a pipe with both ends in the same program. //! Whenever there's a signal, the signal handler writes one byte of garbage data to the write end, //! unless the pipe's already full. The application then can handle the read end. //! //! This has two advantages. First, the real signal action moves outside of the signal handler //! where there are a lot less restrictions. Second, it fits nicely in all kinds of asynchronous //! loops and has less chance of race conditions. //! //! This module offers premade functions for the write end (and doesn't insist that it must be a //! pipe ‒ anything that can be written to is fine ‒ sockets too, therefore `UnixStream::pair` is a //! good candidate). //! //! If you want to integrate with some asynchronous library, plugging streams from `mio-uds` or //! `tokio-uds` libraries should work. //! //! If it looks too low-level for your needs, the [`iterator`](../iterator/) module contains some //! higher-lever interface that also uses a self-pipe pattern under the hood. //! //! # Correct order of handling //! //! A care needs to be taken to avoid race conditions, especially when handling the same signal in //! a loop. Specifically, another signal might come when the action for the previous signal is //! being taken. The correct order is first to clear the content of the pipe (read some/all data //! from it) and then take the action. This way a spurious wakeup can happen (the pipe could wake //! up even when no signal came after the signal was taken, because ‒ it arrived between cleaning //! the pipe and taking the action). Note that some OS primitives (eg. `select`) suffer from //! spurious wakeups themselves (they can claim a FD is readable when it is not true) and blocking //! `read` might return prematurely (with eg. `EINTR`). //! //! The reverse order of first taking the action and then clearing the pipe might lose signals, //! which is usually worse. //! //! This is not a problem with blocking on reading from the pipe (because both the blocking and //! cleaning is the same action), but in case of asynchronous handling it matters. //! //! If you want to combine setting some flags with a self-pipe pattern, the flag needs to be set //! first, then the pipe written. On the read end, first the pipe needs to be cleaned, then the //! flag and then the action taken. This is what the [`Signals`](../iterator/struct.Signals.html) //! structure does internally. //! //! # Write collating //! //! While unlikely if handled correctly, it is possible the write end is full when a signal comes. //! In such case the signal handler simply does nothing. If the write end is full, the read end is //! readable and therefore will wake up. On the other hand, blocking in the signal handler would //! definitely be a bad idea. //! //! However, this also means the number of bytes read from the end might be lower than the number //! of signals that arrived. This should not generally be a problem, since the OS already collates //! signals of the same kind together. //! //! # Examples //! //! This example waits for at last one `SIGUSR1` signal to come before continuing (and //! terminating). It sends the signal to itself, so it correctly terminates. //! //! ```rust //! extern crate libc; //! extern crate signal_hook; //! //! use std::io::{Error, Read}; //! use std::os::unix::net::UnixStream; //! //! fn main() -> Result<(), Error> { //! let (mut read, write) = UnixStream::pair()?; //! signal_hook::pipe::register(signal_hook::SIGUSR1, write)?; //! // This will write into the pipe write end through the signal handler //! unsafe { libc::raise(signal_hook::SIGUSR1) }; //! let mut buff = [0]; //! read.read_exact(&mut buff)?; //! println!("Happily terminating"); //! Ok(()) //! } use std::io::Error; use std::os::unix::io::{AsRawFd, RawFd}; use libc::{self, c_int}; use SigId; struct OwnedFd(RawFd); impl OwnedFd { /// Sets close on exec and nonblock on the inner file descriptor. fn set_flags(&self) -> Result<(), Error> { unsafe { let flags = libc::fcntl(self.as_raw_fd(), libc::F_GETFL, 0); if flags == -1 { return Err(Error::last_os_error()); } let flags = flags | libc::O_NONBLOCK | libc::O_CLOEXEC; if libc::fcntl(self.as_raw_fd(), libc::F_SETFL, flags) == -1 { return Err(Error::last_os_error()); } } Ok(()) } } impl AsRawFd for OwnedFd { fn as_raw_fd(&self) -> RawFd { self.0 } } impl Drop for OwnedFd { fn drop(&mut self) { unsafe { libc::close(self.0); } } } pub(crate) fn wake(pipe: RawFd) { unsafe { // This writes some data into the pipe. // // There are two tricks: // * First, the crazy cast. The first part turns reference into pointer. The second part // turns pointer to u8 into a pointer to void, which is what write requires. // * Second, we ignore errors, on purpose. We don't have any means to handling them. The // two conceivable errors are EBADFD, if someone passes a non-existent file descriptor or // if it is closed. The second is EAGAIN, in which case the pipe is full ‒ there were // many signals, but the reader didn't have time to read the data yet. It'll still get // woken up, so not fitting another letter in it is fine. libc::write(pipe, b"X" as *const _ as *const _, 1); } } /// Registers a write to a self-pipe whenever there's the signal. /// /// In this case, the pipe is taken as the `RawFd`. It is still the caller's responsibility to /// close it. pub fn register_raw(signal: c_int, pipe: RawFd) -> Result { // A trick here: // We want to set the FD non-blocking. But it belongs to the caller. Therefore, we make our own // copy with `dup` to play on instead. let duped = unsafe { libc::dup(pipe) }; if duped == -1 { return Err(Error::last_os_error()); } let duped = OwnedFd(duped); duped.set_flags()?; let action = move || wake(duped.as_raw_fd()); unsafe { ::register(signal, action) } } /// Registers a write to a self-pipe whenever there's the signal. /// /// The ownership of pipe is taken and will be closed whenever the created action is unregistered. /// /// Note that if you want to register the same pipe for multiple signals, there's `try_clone` /// method on many unix socket primitives. pub fn register

(signal: c_int, pipe: P) -> Result where P: AsRawFd + Send + Sync + 'static, { let id = register_raw(signal, pipe.as_raw_fd())?; // Close the original drop(pipe); Ok(id) } #[cfg(test)] mod tests { use std::io::Read; use std::os::unix::net::{UnixDatagram, UnixStream}; use super::*; // Note: multiple tests share the SIGUSR1 signal. This is fine, we only need to know the signal // arrives. It's OK to arrive multiple times, from multiple tests. fn wakeup() { unsafe { assert_eq!(0, libc::raise(libc::SIGUSR1)) } } #[test] fn register_with_socket() -> Result<(), Error> { let (mut read, write) = UnixStream::pair()?; register(libc::SIGUSR1, write)?; read.set_nonblocking(true)?; wakeup(); let mut buff = [0; 1]; read.read_exact(&mut buff)?; assert_eq!(b"X", &buff); Ok(()) } #[test] fn register_dgram_socket() -> Result<(), Error> { let (read, write) = UnixDatagram::pair()?; register(libc::SIGUSR1, write)?; read.set_nonblocking(true)?; wakeup(); let mut buff = [0; 1]; read.recv(&mut buff)?; assert_eq!(b"X", &buff); Ok(()) } #[test] fn register_with_pipe() -> Result<(), Error> { let mut fds = [0; 2]; unsafe { assert_eq!(0, libc::pipe(fds.as_mut_ptr())) }; let read = OwnedFd(fds[0]); let write = OwnedFd(fds[1]); register(libc::SIGUSR1, write)?; read.set_flags()?; wakeup(); let mut buff = [0; 1]; unsafe { assert_eq!( 1, libc::read(read.as_raw_fd(), buff.as_mut_ptr() as *mut _, 1) ) } assert_eq!(b"X", &buff); Ok(()) } } signal-hook-0.1.12/tests/cleanup.rs010064000017500000627000000055141356625303400154000ustar0000000000000000//! Tests for the cleanup module. //! //! The tests work like this: //! //! * The register an alarm, to fail if anything takes too long (which is very much possible here). //! * A fork is done, with the child registering a signal with a NOP and cleanup operation (one or //! the other). //! * The child puts some kind of infinite loop or sleep inside itself, so it never actually //! terminates on the first, but would terminate after the signal. #![cfg(not(windows))] // Forks don't work on Windows, but windows has the same implementation. extern crate libc; extern crate signal_hook; use std::io::Error; use std::ptr; use std::thread; use std::time::Duration; fn do_test(child: C) { unsafe { libc::alarm(10); // Time out the test after 10 seconds and get it killed. match libc::fork() { -1 => panic!("Fork failed: {}", Error::last_os_error()), 0 => { child(); loop { thread::sleep(Duration::from_secs(1)); } } pid => { // Give the child some time to register signals and stuff // We could actually signal that the child is ready by it eg. closing STDOUT, but // this is just a test so we don't really bother. thread::sleep(Duration::from_millis(250)); libc::kill(pid, libc::SIGTERM); // Wait a small bit to make sure the signal got delivered. thread::sleep(Duration::from_millis(50)); // The child is still running, because the first signal got "handled" by being // ignored. let terminated = libc::waitpid(pid, ptr::null_mut(), libc::WNOHANG); assert_eq!(0, terminated, "Process {} terminated prematurely", pid); // But it terminates on the second attempt (we do block on wait here). libc::kill(pid, libc::SIGTERM); let terminated = libc::waitpid(pid, ptr::null_mut(), 0); assert_eq!(pid, terminated); } } } } /// Use automatic cleanup inside the signal handler to get rid of old signals, the aggressive way. #[test] fn cleanup_inside_signal() { fn hook() { unsafe { signal_hook::register(libc::SIGTERM, || ()).unwrap() }; signal_hook::cleanup::register(libc::SIGTERM, vec![libc::SIGTERM]).unwrap(); } do_test(hook); } /// Manually remove the signal handler just after receiving the signal but before going into an /// infinite loop. #[test] fn cleanup_after_signal() { fn hook() { let signals = signal_hook::iterator::Signals::new(&[libc::SIGTERM]).unwrap(); assert_eq!(Some(libc::SIGTERM), signals.into_iter().next()); signal_hook::cleanup::cleanup_signal(libc::SIGTERM).unwrap(); } do_test(hook); } signal-hook-0.1.12/tests/cleanup_indirect.rs010064000017500000627000000016701356625303400172600ustar0000000000000000//! One indirect test for cleanup. //! //! Unlike the ones in cleanup.rs, this one is usable on windows too. But because the library can't //! recover from cleanup, we have just one here. extern crate libc; extern crate signal_hook; use std::sync::atomic::AtomicBool; use std::sync::Arc; use libc::{c_int, raise, sighandler_t, signal}; use signal_hook::SIGTERM; extern "C" fn handler(_: c_int) {} #[test] fn cleanup_indirect() { // Read what the default is. let orig = unsafe { signal(SIGTERM, handler as sighandler_t) }; signal_hook::flag::register(SIGTERM, Arc::new(AtomicBool::new(false))).unwrap(); signal_hook::cleanup::register(SIGTERM, vec![SIGTERM]).unwrap(); // By now, it is switched to something else. unsafe { // This'll change it back to the default due to the cleanup. raise(SIGTERM); // Check it really did. assert_eq!(orig, signal(SIGTERM, handler as sighandler_t)); } } signal-hook-0.1.12/tests/default.rs010064000017500000627000000011031356625303400153630ustar0000000000000000//! Check the hack of SIG_DFL for windows. //! //! Libc doesn't export SIG_DFL on windows. It seems to be 0 on all platforms, though, but just to //! make sure, we observe it is so. We try to read the previous signal on startup and it must be //! the default. extern crate libc; use libc::{sighandler_t, signal, SIGTERM}; const SIG_DFL: sighandler_t = 0; #[test] fn sig_dfl() { unsafe { let prev = signal(SIGTERM, SIG_DFL); assert_eq!(SIG_DFL, prev); } } #[cfg(not(windows))] #[test] fn sig_dfl_static() { assert_eq!(::libc::SIG_DFL, SIG_DFL); } signal-hook-0.1.12/tests/iterator.rs010064000017500000627000000045651351701274400156040ustar0000000000000000#![cfg(not(windows))] extern crate signal_hook; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::mpsc::{self, RecvTimeoutError}; use std::sync::Arc; use std::thread; use std::time::Duration; use signal_hook::iterator::Signals; use signal_hook::{SIGUSR1, SIGUSR2}; #[test] fn signals_close_forever() { // The cloned instances are connected to each other. Closing one closes all. // Closing it terminates the forever that waits for stuff. Well, it terminates all of them. let signals = Signals::new(&[SIGUSR1]).unwrap(); // Detect early terminations. let stopped = Arc::new(AtomicBool::new(false)); let threads = (0..5).map(|_| { let signals_bg = signals.clone(); let stopped_bg = Arc::clone(&stopped); thread::spawn(move || { // Eat all the signals there are (might come from a concurrent test, in theory). // Would wait forever, but it should be terminated by the close below. for _sig in &signals_bg {} stopped_bg.store(true, Ordering::SeqCst); }) }); // Wait a bit… if some thread terminates by itself. thread::sleep(Duration::from_millis(100)); assert!(!stopped.load(Ordering::SeqCst)); signals.close(); // If they don't terminate correctly, the test just keeps running. Not the best way to do // tests, but whatever… for thread in threads { thread.join().unwrap(); } } // A reproducer for #16: if we had the mio-support enabled (which is enabled also by the // tokio-support feature), blocking no longer works. The .wait() would return immediately (an empty // iterator, possibly), .forever() would do a busy loop. // flag) #[test] fn signals_block_wait() { let signals = Signals::new(&[SIGUSR2]).unwrap(); let (s, r) = mpsc::channel(); thread::spawn(move || { // Technically, it may spuriously return early. But it shouldn't be doing it too much, so // we just try to wait multiple times ‒ if they *all* return right away, it is broken. for _ in 0..10 { for _ in signals.wait() { panic!("Someone really did send us SIGUSR2, which breaks the test"); } } let _ = s.send(()); }); let err = r .recv_timeout(Duration::from_millis(100)) .expect_err("Wait didn't wait properly"); assert_eq!(err, RecvTimeoutError::Timeout); } signal-hook-0.1.12/tests/tokio.rs010064000017500000627000000037711356423300300150710ustar0000000000000000#![cfg(not(windows))] #[cfg(feature = "tokio-support")] mod tests { extern crate libc; extern crate signal_hook; extern crate tokio; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; use std::time::{Duration, Instant}; use self::signal_hook::iterator::Signals; use self::tokio::prelude::*; use self::tokio::timer::Interval; fn send_sig(sig: libc::c_int) { unsafe { libc::raise(sig) }; } #[test] fn repeated() { let signals = Signals::new(&[signal_hook::SIGUSR1]) .unwrap() .into_async() .unwrap() .take(20) .map_err(|e| panic!("{}", e)) .for_each(|sig| { assert_eq!(sig, signal_hook::SIGUSR1); send_sig(signal_hook::SIGUSR1); Ok(()) }); send_sig(signal_hook::SIGUSR1); tokio::run(signals); } /// A test where we actually wait for something ‒ the stream/reactor goes to sleep. #[test] fn delayed() { const CNT: usize = 10; let cnt = Arc::new(AtomicUsize::new(0)); let inc_cnt = Arc::clone(&cnt); let signals = Signals::new(&[signal_hook::SIGUSR1, signal_hook::SIGUSR2]) .unwrap() .into_async() .unwrap() .filter(|sig| *sig == signal_hook::SIGUSR2) .take(CNT as u64) .map_err(|e| panic!("{}", e)) .for_each(move |_| { inc_cnt.fetch_add(1, Ordering::Relaxed); Ok(()) }); let senders = Interval::new(Instant::now(), Duration::from_millis(250)) .map_err(|e| panic!("{}", e)) .for_each(|_| { send_sig(signal_hook::SIGUSR2); Ok(()) }); let both = signals.select(senders).map(|_| ()).map_err(|_| ()); tokio::run(both); // Just make sure it didn't terminate prematurely assert_eq!(CNT, cnt.load(Ordering::Relaxed)); } } signal-hook-0.1.12/tests/version.rs010064000017500000627000000003211331364546300154260ustar0000000000000000#[macro_use] extern crate version_sync; #[test] fn test_readme_deps() { assert_markdown_deps_updated!("README.md"); } #[test] fn test_html_root_url() { assert_html_root_url_updated!("src/lib.rs"); } signal-hook-0.1.12/.cargo_vcs_info.json0000644000000001121356626316300134330ustar00{ "git": { "sha1": "94dd888de3c2f1f5d4091968edf87fbf6b050190" } }