diff options
Diffstat (limited to 'vendor/signal-hook')
27 files changed, 4269 insertions, 0 deletions
diff --git a/vendor/signal-hook/.cargo-checksum.json b/vendor/signal-hook/.cargo-checksum.json new file mode 100644 index 000000000..9c6dd5450 --- /dev/null +++ b/vendor/signal-hook/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"20a9b9bd056e5fbb980b7c5a7fc706dd32309743eeff23c5d4228ac10fca5b7b","Cargo.lock":"284dcdbc909099e591c59d059e66aa435d463c232f5fd0759b9732780d27fd8f","Cargo.toml":"41ccc6b0e364bc0da0a42496fa079037edad3f3bdb711a944f3332db89a9e18d","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"503558bfefe66ca15e4e3f7955b3cb0ec87fd52f29bf24b336af7bd00e946d5c","README.md":"be97b822f26b642165c4fac3ed6a515f2c522f30c12a2011aa3b5cab1eb988d0","build.rs":"3a95a69d2921f1c28922a141a671e23a061f358b6d831350043003e13ef96463","ci-check.sh":"65f6e254cca1adf4579998fa393521cef8bc5bfbfb79b9fb430e1814a5a7c091","examples/print.rs":"ff4e0aeaf2533e7b48edec866cd6b65021a1e588e22d9a443a631d750daa36a0","rustfmt.toml":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","src/flag.rs":"c240f03b5895a24803192a720ac3280c43d83867ca414e0622f53f90d287d07f","src/iterator/backend.rs":"98096e6fa7c3187c81acf8bf68b4aef013019a993dcdcde37b235bdfaf3c1561","src/iterator/exfiltrator/mod.rs":"c5476b32f00094e7556350c79bff7cec88e890750a42b613a5bf00e33234311f","src/iterator/exfiltrator/origin.rs":"ada8f6289c9b31d523f3cc9e02d533a3f348cfad6f5fc59ab929f851816ed156","src/iterator/exfiltrator/raw.rs":"22085d408ed660d6a2cb744f2c1bd321dbe261dfcc8858c41ad3ff9d367609c9","src/iterator/mod.rs":"d0c5e02df18ab578f98d4fa8b3c0d6c1f74a9c76033468216cb1704c946eb5f2","src/lib.rs":"968a13e57ba4c5a05f6a73aab83a6f4fae72d79a235129e09700946141c6c238","src/low_level/channel.rs":"7561da67226f0c668adc06d398d5a6f0f84a67b90092067e14359e9ee05cdac1","src/low_level/extract.c":"7583e69e6d0e57893dc6813ec6a519a83c86f9d1e4129812eacaca630dcf1c9d","src/low_level/mod.rs":"91b2a8995a7dcb71cf50bc5ead532e5ee706c77b7af99dbf6fc55c4a1516f03f","src/low_level/pipe.rs":"544d780577ba802af32abd7a075a3702f36b644d16baf3c2708ccec373b01c61","src/low_level/siginfo.rs":"3a416031a654add7b39a2a6c0328e6c60dbf33ca972a45ef11eaf198615a0aaf","src/low_level/signal_details.rs":"93d68af97fa45435e0236e96412eeea60ac2715eac0aa0648f27837537a722f1","tests/default.rs":"2e6e400990d31a5968f6909278e9cf20b75ba7f1a92b8485122ac790a2e94a44","tests/iterator.rs":"1533f9722c047a221a6e8903d179cace76c395fff54df010e42fbcaabeca7bc9","tests/shutdown.rs":"3ca8dbf94eead616bd47968f029a91c6bdffc9fb44be3f004d6e8fe2ac46db00"},"package":"732768f1176d21d09e076c23a93123d40bba92d50c4058da34d45c8de8e682b9"}
\ No newline at end of file diff --git a/vendor/signal-hook/CHANGELOG.md b/vendor/signal-hook/CHANGELOG.md new file mode 100644 index 000000000..7277e7631 --- /dev/null +++ b/vendor/signal-hook/CHANGELOG.md @@ -0,0 +1,256 @@ +# 0.3.15 +# signal-hook-registry-1.4.1 + +* AIX support (experimental/not guaranteed to work). + +# 0.3.14 + +* Added the SIGINFO signal (where available). + +# signal-hook-mio-0.2.3 + +* Support for mio 0.8 + +# signal-hook-async-std-0.2.2 +# signal-hook-tokio-0.3.1 + +* Fix support for SignalsInfo with non-default info extractors. + +# 0.3.13 + +* Add haiku support. + +# 0.3.12 + +* Fix accidentally broken windows build. + +# 0.3.11 + +* Provide fallback sigaddset, sigemptyset on certain androids, as they are + missing them. + +# 0.3.10 + +* Doc link fixes. + +# 0.3.9 + +* Deliver SIGCHLD even on stop/continue. + +# 0.3.8 + +* Fix docs.rs build. + +# 0.3.7 + +* Unmask a signal in default emulation if it is termination. + +# mio-0.2.2 + +* The same fix, but for the 0.6 support 😇. + +# mio-0.2.1 + +* Fix example: handle ErrorKind::Interrupted inside poll. It's very likely to + happen, when we are waiting for signals there. + +# 0.3.6 + +* Fix the labels on docs.rs :-|. + +# 0.3.5 + +* Doc: include the features & these little labels inside docs. + +# signal-hook-async-std-0.2.1 + +* Dependency updates ‒ no longer depends on the whole async-std, but only on + some smaller dependencies of it (`async-io`, `futures-lite`). This might make + it work even outside of async-std context. + +# signal-hook-tokio-0.3.0 + +* Support for tokio 1.0. + +# 0.3.4 + +* Fix feature dependencies (`iterator` depends on `channel`). + +# 0.3.3 + +* `low_level::emulate_default_handler` to emulate whatever default handler would + do. +* `low_level::signal_name` to look up human readable name. +* The `Origin`'s debug output now contains the human readable name of the + signal. + +# 0.3.2 + +* Allow extracting Origin from the raw `siginfo_t` structure by hand, without + needing an iterator. +* Folding the signal-hook-sys inline (but still compiling C code only + conditionally). +* `WithRawSiginfo` extractor (to get hands on the raw `siginfo_t`). +* Bugfix: Don't leak on WithOrigin destruction. + +# 0.3.1 + +* Use caret dependencies where appropriate (to allow upgrades on + signal-hook-registry). + +# async-std-0.2.0 + +* No longer depends on `futures`. + +# 0.3.0 + +* The `cleanup` module is gone, it was not a good API. Replaced by conditional + termination in `flag`. +* Some abstractions/patterns are moved to `low_level` submodule, as they are + considered building blocks, not for direct use (`register`, `pipe`, + `channel`). +* The signal constants are moved to a submodule (`consts`), together with few + more constants, to not clutter the root. +* The forever iterator no longer consumes. + +# registry-1.3.0 + +* The `unregister_signal` in is deprecated, without a replacement. + +# 0.2.2 + +* Extractor for the origin of a signal (PID, UID, what caused it). +* Fixing some doc links on re-exports. + +# 0.2.1 + +* Allow turning the iterator module off (the `iterator` feature, part of default + features). This would allow compiling the crate on 1.31.0. + +# 0.2.0 + +* Bump minimal rustc version to 1.36.0 (signal-hook-registry still builds with + 1.26.0). +* (Breaking) Support for exfiltrators ‒ ability to return more than just the + signal number from the iterator and streams. Nothing more is implemented yet, + but the place to put it is reserved in the API. +* (Breaking) `pipe::register_raw` now takes ownership and tries to use send + first, falls back to `O_NONBLOCK` and `write` on failure. +* (Breaking) All async support is pulled out into separate crates, to decouple + from the async runtime release cycles on the main `signal-hook` crate. +* Inner parts of the `Iterator` are now exposed in + `signal_hook::iterator::backend`, to support the async crates. + +# registry-1.2.2 + +* Drop dependency on arc-swap (only very small subset used and arc-swap would + like to drop that part anyway). + +# registry-1.2.1 + +* Abort instead of panicking if the OS gives us NULL as siginfo (which is + illegal). Panicking would be UB. + +# 0.1.16 + +* Fix possible blocking in signal handler registered by `Signals`. + +# 0.1.15 + +* Make `Signals` work in edge-triggered mode in mio too, by always draining + everything from the socket. Needed, because mio 0.7 doesn't have + level-triggered any more. + +# 0.1.14 + +* `mio-0_7-support` feature for use with mio 0.7.0+. +* Bump minimal rustc version to 1.31.0 (signal-hook-registry can still build + with 1.26.0). + +# 0.1.13 + +* Some doc clarifications. + +# 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. diff --git a/vendor/signal-hook/Cargo.lock b/vendor/signal-hook/Cargo.lock new file mode 100644 index 000000000..d969becf3 --- /dev/null +++ b/vendor/signal-hook/Cargo.lock @@ -0,0 +1,260 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" + +[[package]] +name = "lock_api" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +dependencies = [ + "bitflags", +] + +[[package]] +name = "rustversion" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "serial_test" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d19dbfb999a147cedbfe82f042eb9555f5b0fa4ef95ee4570b74349103d9c9f4" +dependencies = [ + "lazy_static", + "log", + "parking_lot", + "serial_test_derive", +] + +[[package]] +name = "serial_test_derive" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb9e2050b2be1d681f8f1c1a528bcfe4e00afa2d8995f713974f5333288659f2" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + +[[package]] +name = "signal-hook" +version = "0.3.15" +dependencies = [ + "cc", + "libc", + "serial_test", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +dependencies = [ + "libc", +] + +[[package]] +name = "smallvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" + +[[package]] +name = "syn" +version = "1.0.96" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0748dd251e24453cb8717f0354206b91557e4ec8703673a4b30208f2abaf1ebf" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" diff --git a/vendor/signal-hook/Cargo.toml b/vendor/signal-hook/Cargo.toml new file mode 100644 index 000000000..45e3e13f6 --- /dev/null +++ b/vendor/signal-hook/Cargo.toml @@ -0,0 +1,66 @@ +# 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 are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +name = "signal-hook" +version = "0.3.15" +authors = [ + "Michal 'vorner' Vaner <vorner@vorner.cz>", + "Thomas Himmelstoss <thimm@posteo.de>", +] +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 +rustdoc-args = [ + "--cfg", + "docsrs", +] + +[dependencies.libc] +version = "^0.2" + +[dependencies.signal-hook-registry] +version = "^1.4" + +[dev-dependencies.serial_test] +version = "^0.7" + +[build-dependencies.cc] +version = "^1" +optional = true + +[features] +channel = [] +default = [ + "channel", + "iterator", +] +extended-siginfo = [ + "channel", + "iterator", + "extended-siginfo-raw", +] +extended-siginfo-raw = ["cc"] +iterator = ["channel"] + +[badges.maintenance] +status = "actively-developed" diff --git a/vendor/signal-hook/LICENSE-APACHE b/vendor/signal-hook/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/vendor/signal-hook/LICENSE-APACHE @@ -0,0 +1,201 @@ + 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. diff --git a/vendor/signal-hook/LICENSE-MIT b/vendor/signal-hook/LICENSE-MIT new file mode 100644 index 000000000..ebe0bc91e --- /dev/null +++ b/vendor/signal-hook/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (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. diff --git a/vendor/signal-hook/README.md b/vendor/signal-hook/README.md new file mode 100644 index 000000000..71a3d2701 --- /dev/null +++ b/vendor/signal-hook/README.md @@ -0,0 +1,70 @@ +# Signal-hook + +[![Actions Status](https://github.com/vorner/signal-hook/workflows/test/badge.svg)](https://github.com/vorner/signal-hook/actions) +[![codecov](https://codecov.io/gh/vorner/signal-hook/branch/master/graph/badge.svg?token=3KA3R2D9fV)](https://codecov.io/gh/vorner/signal-hook) +[![docs](https://docs.rs/signal-hook/badge.svg)](https://docs.rs/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, available from +safe Rust. + +For further details, see the [documentation](https://docs.rs/signal-hook). + +## Example + +(This likely does a lot more than you need in each individual application, it's +more of a show-case of what everything is possible, not of what you need to do +each time). + +```rust +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::consts::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). + } + Ok(()) +} +``` + +## 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. diff --git a/vendor/signal-hook/build.rs b/vendor/signal-hook/build.rs new file mode 100644 index 000000000..82545f1ec --- /dev/null +++ b/vendor/signal-hook/build.rs @@ -0,0 +1,9 @@ +#[cfg(feature = "extended-siginfo-raw")] +fn main() { + cc::Build::new() + .file("src/low_level/extract.c") + .compile("extract"); +} + +#[cfg(not(feature = "extended-siginfo-raw"))] +fn main() {} diff --git a/vendor/signal-hook/ci-check.sh b/vendor/signal-hook/ci-check.sh new file mode 100755 index 000000000..05879b651 --- /dev/null +++ b/vendor/signal-hook/ci-check.sh @@ -0,0 +1,31 @@ +#!/bin/sh + +# We try to support some older versions of rustc. However, the support is +# tiered a bit. Our dev-dependencies do *not* guarantee that old minimal +# version. So we don't do tests on the older ones. Also, the +# signal-hook-registry supports older rustc than we signal-hook. + +set -ex + +rm -f Cargo.lock +cargo build --all --exclude signal-hook-async-std --exclude signal-hook-tokio + +if [ "$RUST_VERSION" = 1.36.0 ] ; then + exit +fi + +if [ "$OS" = "windows-latest" ] || [ "$RUST_VERSION" = 1.40.0 ]; then + # The async support crates rely on the iterator module + # which isn't available for windows. So exclude them + # from the build. + + # Also, some dependencies of the runtimes don't like 1.40. + EXCLUDE_FROM_BUILD="--exclude signal-hook-mio --exclude signal-hook-tokio --exclude signal-hook-async-std" +else + EXCLUDE_FROM_BUILD="" +fi + +export RUSTFLAGS="-D warnings" + +cargo test --all --all-features $EXCLUDE_FROM_BUILD +cargo test --all $EXCLUDE_FROM_BUILD diff --git a/vendor/signal-hook/examples/print.rs b/vendor/signal-hook/examples/print.rs new file mode 100644 index 000000000..4007f9171 --- /dev/null +++ b/vendor/signal-hook/examples/print.rs @@ -0,0 +1,27 @@ +use libc::c_int; +use signal_hook::consts::signal::*; +use signal_hook::low_level; + +use std::io::Error; + +#[cfg(feature = "extended-siginfo")] +type Signals = + signal_hook::iterator::SignalsInfo<signal_hook::iterator::exfiltrator::origin::WithOrigin>; + +#[cfg(not(feature = "extended-siginfo"))] +use signal_hook::iterator::Signals; + +fn main() -> Result<(), Error> { + const SIGNALS: &[c_int] = &[ + SIGTERM, SIGQUIT, SIGINT, SIGTSTP, SIGWINCH, SIGHUP, SIGCHLD, SIGCONT, + ]; + let mut sigs = Signals::new(SIGNALS)?; + for signal in &mut sigs { + eprintln!("Received signal {:?}", signal); + #[cfg(feature = "extended-siginfo")] + let signal = signal.signal; + // After printing it, do whatever the signal was supposed to do in the first place + low_level::emulate_default_handler(signal)?; + } + Ok(()) +} diff --git a/vendor/signal-hook/rustfmt.toml b/vendor/signal-hook/rustfmt.toml new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/vendor/signal-hook/rustfmt.toml diff --git a/vendor/signal-hook/src/flag.rs b/vendor/signal-hook/src/flag.rs new file mode 100644 index 000000000..8573fcd7f --- /dev/null +++ b/vendor/signal-hook/src/flag.rs @@ -0,0 +1,283 @@ +//! 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`][crate::low_level::pipe] and [`iterator`][crate::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 +//! use std::io::Error; +//! use std::sync::Arc; +//! use std::sync::atomic::{AtomicUsize, Ordering}; +//! +//! use signal_hook::consts::signal::*; +//! use signal_hook::flag as signal_flag; +//! +//! fn main() -> Result<(), Error> { +//! let term = Arc::new(AtomicUsize::new(0)); +//! const SIGTERM_U: usize = SIGTERM as usize; +//! const SIGINT_U: usize = SIGINT as usize; +//! # #[cfg(not(windows))] +//! const SIGQUIT_U: usize = SIGQUIT as usize; +//! signal_flag::register_usize(SIGTERM, Arc::clone(&term), SIGTERM_U)?; +//! signal_flag::register_usize(SIGINT, Arc::clone(&term), SIGINT_U)?; +//! # #[cfg(not(windows))] +//! signal_flag::register_usize(SIGQUIT, Arc::clone(&term), SIGQUIT_U)?; +//! +//! # // Hack to terminate the example when run as a doc-test. +//! # term.store(SIGTERM_U, Ordering::Relaxed); +//! loop { +//! match term.load(Ordering::Relaxed) { +//! 0 => { +//! // Do some useful stuff here +//! } +//! SIGTERM_U => { +//! eprintln!("Terminating on the TERM signal"); +//! break; +//! } +//! SIGINT_U => { +//! eprintln!("Terminating on the INT signal"); +//! break; +//! } +//! # #[cfg(not(windows))] +//! SIGQUIT_U => { +//! 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 +//! use std::io::Error; +//! use std::sync::Arc; +//! use std::sync::atomic::{AtomicBool, Ordering}; +//! use std::thread; +//! use std::time::Duration; +//! +//! use signal_hook::consts::signal::*; +//! use signal_hook::low_level::raise; +//! +//! fn main() -> Result<(), Error> { +//! let got = Arc::new(AtomicBool::new(false)); +//! # #[cfg(not(windows))] +//! signal_hook::flag::register(SIGUSR1, Arc::clone(&got))?; +//! # #[cfg(windows)] +//! # signal_hook::flag::register(SIGTERM, Arc::clone(&got))?; +//! # #[cfg(not(windows))] +//! raise(SIGUSR1).unwrap(); +//! # #[cfg(windows)] +//! # raise(SIGTERM).unwrap(); +//! // 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 +//! use std::io::Error; +//! use std::sync::Arc; +//! use std::sync::atomic::{AtomicBool, Ordering}; +//! +//! use signal_hook::consts::signal::*; +//! 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(SIGHUP, Arc::clone(&reload))?; +//! signal_flag::register(SIGINT, Arc::clone(&term))?; +//! signal_flag::register(SIGTERM, Arc::clone(&term))?; +//! # #[cfg(not(windows))] +//! signal_flag::register(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, EINVAL}; + +use crate::{low_level, SigId}; + +/// Registers an action to set the flag to `true` whenever the given signal arrives. +/// +/// # Panics +/// +/// If the signal is one of the forbidden. +pub fn register(signal: c_int, flag: Arc<AtomicBool>) -> Result<SigId, Error> { + // 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 { low_level::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<AtomicUsize>, value: usize) -> Result<SigId, Error> { + unsafe { low_level::register(signal, move || flag.store(value, Ordering::SeqCst)) } +} + +/// Terminate the application on a signal if the given condition is true. +/// +/// This can be used for different use cases. One of them (with the condition being always true) is +/// just unconditionally terminate on the given signal. +/// +/// Another is being able to turn on and off the behaviour by the shared flag. +/// +/// The last one is handling double CTRL+C ‒ if the user presses CTRL+C, we would like to start a +/// graceful shutdown. But if anything ever gets stuck in the shutdown, second CTRL+C (or other +/// such termination signal) should terminate the application without further delay. +/// +/// To do that, one can combine this with [`register`]. On the first run, the flag is `false` and +/// this doesn't terminate. But then the flag is set to true during the first run and „arms“ the +/// shutdown on the second run. Note that it matters in which order the actions are registered (the +/// shutdown must go first). And yes, this also allows asking the user „Do you want to terminate“ +/// and disarming the abrupt shutdown if the user answers „No“. +/// +/// # Panics +/// +/// If the signal is one of the forbidden. +pub fn register_conditional_shutdown( + signal: c_int, + status: c_int, + condition: Arc<AtomicBool>, +) -> Result<SigId, Error> { + let action = move || { + if condition.load(Ordering::SeqCst) { + low_level::exit(status); + } + }; + unsafe { low_level::register(signal, action) } +} + +/// Conditionally runs an emulation of the default action on the given signal. +/// +/// If the provided condition is true at the time of invoking the signal handler, the equivalent of +/// the default action of the given signal is run. It is a bit similar to +/// [`register_conditional_shutdown`], except that it doesn't terminate for non-termination +/// signals, it runs their default handler. +/// +/// # Panics +/// +/// If the signal is one of the forbidden +/// +/// # Errors +/// +/// Similarly to the [`emulate_default_handler`][low_level::emulate_default_handler] function, this +/// one looks the signal up in a table. If it is unknown, an error is returned. +/// +/// Additionally to that, any errors that can be caused by a registration of a handler can happen +/// too. +pub fn register_conditional_default( + signal: c_int, + condition: Arc<AtomicBool>, +) -> Result<SigId, Error> { + // Verify we know about this particular signal. + low_level::signal_name(signal).ok_or_else(|| Error::from_raw_os_error(EINVAL))?; + let action = move || { + if condition.load(Ordering::SeqCst) { + let _ = low_level::emulate_default_handler(signal); + } + }; + unsafe { low_level::register(signal, action) } +} + +#[cfg(test)] +mod tests { + use std::sync::atomic; + use std::time::{Duration, Instant}; + + use super::*; + use crate::consts::signal::*; + + fn self_signal() { + #[cfg(not(windows))] + const SIG: c_int = SIGUSR1; + #[cfg(windows)] + const SIG: c_int = SIGTERM; + crate::low_level::raise(SIG).unwrap(); + } + + fn wait_flag(flag: &AtomicBool) -> bool { + let start = Instant::now(); + while !flag.load(Ordering::Relaxed) { + // Replaced by hint::spin_loop, but we want to support older compiler + #[allow(deprecated)] + 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(crate::SIGTERM, Arc::clone(&flag)).unwrap(); + self_signal(); + assert!(wait_flag(&flag)); + // But stops working after it is unregistered. + assert!(crate::low_level::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)); + } + + // The shutdown is tested in tests/shutdown.rs +} diff --git a/vendor/signal-hook/src/iterator/backend.rs b/vendor/signal-hook/src/iterator/backend.rs new file mode 100644 index 000000000..2ed4bf93a --- /dev/null +++ b/vendor/signal-hook/src/iterator/backend.rs @@ -0,0 +1,494 @@ +//! A backend module for implementing the iterator like +//! [`iterator`][crate::iterator] module and the asynchronous +//! adapter crates. +//! +//! This module contains generic types which abstract over the concrete +//! IO type for the self-pipe. The motivation for having this abstraction +//! are the adapter crates for different asynchronous runtimes. The runtimes +//! provide their own wrappers for [`std::os::unix::net::UnixStream`] +//! which should be used as the internal self pipe. But large parts of the +//! remaining functionality doesn't depend directly onto the IO type and can +//! be reused. +//! +//! See also the [`SignalDelivery::with_pipe`] method for more information +//! about requirements the IO types have to fulfill. +//! +//! As a regular user you shouldn't need to use the types in this module. +//! Use the [`Signals`][crate::iterator::Signals] struct or one of the types +//! contained in the adapter libraries instead. + +use std::borrow::{Borrow, BorrowMut}; +use std::fmt::{Debug, Formatter, Result as FmtResult}; +use std::io::Error; +use std::mem::MaybeUninit; +use std::os::unix::io::AsRawFd; +use std::ptr; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::{Arc, Mutex}; + +use libc::{self, c_int}; + +use super::exfiltrator::Exfiltrator; +use crate::low_level::pipe::{self, WakeMethod}; +use crate::SigId; + +/// Maximal signal number we support. +const MAX_SIGNUM: usize = 128; + +trait SelfPipeWrite: Debug + Send + Sync { + fn wake_readers(&self); +} + +impl<W: AsRawFd + Debug + Send + Sync> SelfPipeWrite for W { + fn wake_readers(&self) { + pipe::wake(self.as_raw_fd(), WakeMethod::Send); + } +} + +#[derive(Debug)] +struct DeliveryState { + closed: AtomicBool, + registered_signal_ids: Mutex<Vec<Option<SigId>>>, +} + +impl DeliveryState { + fn new() -> Self { + let ids = (0..MAX_SIGNUM).map(|_| None).collect(); + Self { + closed: AtomicBool::new(false), + registered_signal_ids: Mutex::new(ids), + } + } +} + +impl Drop for DeliveryState { + fn drop(&mut self) { + let lock = self.registered_signal_ids.lock().unwrap(); + for id in lock.iter().filter_map(|s| *s) { + crate::low_level::unregister(id); + } + } +} + +struct PendingSignals<E: Exfiltrator> { + exfiltrator: E, + slots: [E::Storage; MAX_SIGNUM], +} + +impl<E: Exfiltrator> PendingSignals<E> { + fn new(exfiltrator: E) -> Self { + // Unfortunately, Default is not implemented for long arrays :-( + // + // Note that if the default impl panics, the already existing instances are leaked. + let mut slots = MaybeUninit::<[E::Storage; MAX_SIGNUM]>::uninit(); + for i in 0..MAX_SIGNUM { + unsafe { + let slot: *mut E::Storage = slots.as_mut_ptr() as *mut _; + let slot = slot.add(i); + ptr::write(slot, E::Storage::default()); + } + } + + Self { + exfiltrator, + slots: unsafe { slots.assume_init() }, + } + } +} + +/// An internal trait to hide adding new signals into a Handle behind a dynamic dispatch. +trait AddSignal: Debug + Send + Sync { + fn add_signal( + self: Arc<Self>, + write: Arc<dyn SelfPipeWrite>, + signal: c_int, + ) -> Result<SigId, Error>; +} + +// Implemented manually because 1.36.0 doesn't yet support Debug for [X; BIG_NUMBER]. +impl<E: Exfiltrator> Debug for PendingSignals<E> { + fn fmt(&self, fmt: &mut Formatter) -> FmtResult { + fmt.debug_struct("PendingSignals") + .field("exfiltrator", &self.exfiltrator) + // While the array does not, the slice does implement Debug + .field("slots", &&self.slots[..]) + .finish() + } +} + +impl<E: Exfiltrator> AddSignal for PendingSignals<E> { + fn add_signal( + self: Arc<Self>, + write: Arc<dyn SelfPipeWrite>, + signal: c_int, + ) -> Result<SigId, 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, + ); + assert!( + self.exfiltrator.supports_signal(signal), + "Signal {} not supported by exfiltrator {:?}", + signal, + self.exfiltrator, + ); + self.exfiltrator.init(&self.slots[signal as usize], signal); + + let action = move |act: &_| { + let slot = &self.slots[signal as usize]; + let ex = &self.exfiltrator; + ex.store(slot, signal, act); + write.wake_readers(); + }; + let id = unsafe { signal_hook_registry::register_sigaction(signal, action) }?; + Ok(id) + } +} + +/// A struct to control an instance of an associated type +/// (like for example [`Signals`][super::Signals]). +/// +/// It allows to register more signal handlers and to shutdown the signal +/// delivery. You can [`clone`][Handle::clone] this type which isn't a +/// very expensive operation. The cloned instances can be shared between +/// multiple threads. +#[derive(Debug, Clone)] +pub struct Handle { + pending: Arc<dyn AddSignal>, + write: Arc<dyn SelfPipeWrite>, + delivery_state: Arc<DeliveryState>, +} + +impl Handle { + fn new<W>(write: W, pending: Arc<dyn AddSignal>) -> Self + where + W: 'static + SelfPipeWrite, + { + Self { + pending, + write: Arc::new(write), + delivery_state: Arc::new(DeliveryState::new()), + } + } + + /// Registers another signal to the set watched by the associated 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. + /// + /// # Panics + /// + /// * If the given signal is [forbidden][crate::FORBIDDEN]. + /// * If the signal number is negative or larger than internal limit. The limit should be + /// larger than any supported signal the OS supports. + /// * If the relevant [`Exfiltrator`] does not support this particular signal. The default + /// [`SignalOnly`] one supports all signals. + pub fn add_signal(&self, signal: c_int) -> Result<(), Error> { + let mut lock = self.delivery_state.registered_signal_ids.lock().unwrap(); + // Already registered, ignoring + if lock[signal as usize].is_some() { + return Ok(()); + } + + let id = Arc::clone(&self.pending).add_signal(Arc::clone(&self.write), signal)?; + + lock[signal as usize] = Some(id); + + Ok(()) + } + + /// Closes the associated instance. + /// + /// This is meant to signalize termination of the signal delivery process. + /// After calling close: + /// + /// * [`is_closed`][Handle::is_closed] will return true. + /// * All currently blocking operations of associated instances + /// are interrupted and terminate. + /// * Any further operations will not block. + /// * Further signals may or may not be returned from the iterators. However, if any are + /// returned, these are real signals that happened. + /// + /// The goal is to be able to shut down any background thread that handles only the signals. + pub fn close(&self) { + self.delivery_state.closed.store(true, Ordering::SeqCst); + self.write.wake_readers(); + } + + /// Is it closed? + /// + /// See [`close`][Handle::close]. + pub fn is_closed(&self) -> bool { + self.delivery_state.closed.load(Ordering::SeqCst) + } +} + +/// A struct for delivering received signals to the main program flow. +/// The self-pipe IO type is generic. See the +/// [`with_pipe`][SignalDelivery::with_pipe] method for requirements +/// for the IO type. +#[derive(Debug)] +pub struct SignalDelivery<R, E: Exfiltrator> { + read: R, + handle: Handle, + pending: Arc<PendingSignals<E>>, +} + +impl<R, E: Exfiltrator> SignalDelivery<R, E> +where + R: 'static + AsRawFd + Send + Sync, +{ + /// Creates the `SignalDelivery` structure. + /// + /// The read and write arguments must be the ends of a suitable pipe type. These are used + /// for communication between the signal handler and main program flow. + /// + /// Registers all the signals listed. The same restrictions (panics, errors) apply as with + /// [`add_signal`][Handle::add_signal]. + /// + /// # Requirements for the pipe type + /// + /// * Must support [`send`](https://man7.org/linux/man-pages/man2/send.2.html) for + /// asynchronously writing bytes to the write end + /// * Must support [`recv`](https://man7.org/linux/man-pages/man2/recv.2.html) for + /// reading bytes from the read end + /// + /// So UnixStream is a good choice for this. + pub fn with_pipe<I, S, W>(read: R, write: W, exfiltrator: E, signals: I) -> Result<Self, Error> + where + I: IntoIterator<Item = S>, + S: Borrow<c_int>, + W: 'static + AsRawFd + Debug + Send + Sync, + { + let pending = Arc::new(PendingSignals::new(exfiltrator)); + let pending_add_signal = Arc::clone(&pending); + let handle = Handle::new(write, pending_add_signal); + let me = Self { + read, + handle, + pending, + }; + for sig in signals { + me.handle.add_signal(*sig.borrow())?; + } + Ok(me) + } + + /// Get a reference to the read end of the self pipe + /// + /// You may use this method to register the underlying file descriptor + /// with an eventing system (e. g. epoll) to get notified if there are + /// bytes in the pipe. If the event system reports the file descriptor + /// ready for reading you can then call [`pending`][SignalDelivery::pending] + /// to get the arrived signals. + pub fn get_read(&self) -> &R { + &self.read + } + + /// Get a mutable reference to the read end of the self pipe + /// + /// See the [`get_read`][SignalDelivery::get_read] method for some additional + /// information. + pub fn get_read_mut(&mut self) -> &mut R { + &mut self.read + } + + /// Drains all data from the internal self-pipe. This method will never block. + fn flush(&mut self) { + const SIZE: usize = 1024; + let mut buff = [0u8; SIZE]; + + unsafe { + // Draining the data in the self pipe. 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. + #[cfg(target_os = "aix")] + let nowait_flag = libc::MSG_NONBLOCK; + #[cfg(not(target_os = "aix"))] + let nowait_flag = libc::MSG_DONTWAIT; + while libc::recv( + self.read.as_raw_fd(), + buff.as_mut_ptr() as *mut libc::c_void, + SIZE, + nowait_flag, + ) > 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 `SignalDelivery` 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(&mut self) -> Pending<E> { + self.flush(); + Pending::new(Arc::clone(&self.pending)) + } + + /// Checks the reading end of the self pipe for available signals. + /// + /// If there are no signals available or this instance was already closed it returns + /// [`Option::None`]. If there are some signals it returns a [`Pending`] + /// instance wrapped inside a [`Option::Some`]. However, due to implementation details, + /// this still can produce an empty iterator. + /// + /// This method doesn't check the reading end by itself but uses the passed in callback. + /// This method blocks if and only if the callback blocks trying to read some bytes. + pub fn poll_pending<F>(&mut self, has_signals: &mut F) -> Result<Option<Pending<E>>, Error> + where + F: FnMut(&mut R) -> Result<bool, Error>, + { + if self.handle.is_closed() { + return Ok(None); + } + + match has_signals(self.get_read_mut()) { + Ok(false) => Ok(None), + Ok(true) => Ok(Some(self.pending())), + Err(err) => Err(err), + } + } + + /// Get a [`Handle`] for this `SignalDelivery` instance. + /// + /// This can be used to add further signals or close the whole + /// signal delivery mechanism. + pub fn handle(&self) -> Handle { + self.handle.clone() + } +} + +/// The iterator of one batch of signals. +/// +/// This is returned by the [`pending`][SignalDelivery::pending] method. +#[derive(Debug)] +pub struct Pending<E: Exfiltrator> { + pending: Arc<PendingSignals<E>>, + position: usize, +} + +impl<E: Exfiltrator> Pending<E> { + fn new(pending: Arc<PendingSignals<E>>) -> Self { + Self { + pending, + position: 0, + } + } +} + +impl<E: Exfiltrator> Iterator for Pending<E> { + type Item = E::Output; + + fn next(&mut self) -> Option<E::Output> { + while self.position < self.pending.slots.len() { + let sig = self.position; + let slot = &self.pending.slots[sig]; + let result = self.pending.exfiltrator.load(slot, sig as c_int); + if result.is_some() { + return result; + } else { + self.position += 1; + } + } + + None + } +} + +/// Possible results of the [`poll_signal`][SignalIterator::poll_signal] function. +pub enum PollResult<O> { + /// A signal arrived + Signal(O), + /// There are no signals yet but there may arrive some in the future + Pending, + /// The iterator was closed. There won't be any signals reported from now on. + Closed, + /// An error happened during polling for arrived signals. + Err(Error), +} + +/// An infinite iterator of received signals. +pub struct SignalIterator<SD, E: Exfiltrator> { + signals: SD, + iter: Pending<E>, +} + +impl<SD, E: Exfiltrator> SignalIterator<SD, E> { + /// Create a new infinite iterator for signals registered with the passed + /// in [`SignalDelivery`] instance. + pub fn new<R>(mut signals: SD) -> Self + where + SD: BorrowMut<SignalDelivery<R, E>>, + R: 'static + AsRawFd + Send + Sync, + { + let iter = signals.borrow_mut().pending(); + Self { signals, iter } + } + + /// Return a signal if there is one or tell the caller that there is none at the moment. + /// + /// You have to pass in a callback which checks the underlying reading end of the pipe if + /// there may be any pending signals. This callback may or may not block. If the callback + /// returns [`true`] this method will try to fetch the next signal and return it as a + /// [`PollResult::Signal`]. If the callback returns [`false`] the method will return + /// [`PollResult::Pending`] and assume it will be called again at a later point in time. + /// The callback may be called any number of times by this function. + /// + /// If the iterator was closed by the [`close`][Handle::close] method of the associtated + /// [`Handle`] this method will return [`PollResult::Closed`]. + pub fn poll_signal<R, F>(&mut self, has_signals: &mut F) -> PollResult<E::Output> + where + SD: BorrowMut<SignalDelivery<R, E>>, + R: 'static + AsRawFd + Send + Sync, + F: FnMut(&mut R) -> Result<bool, Error>, + { + // The loop is necessary because it is possible that a signal was already consumed + // by a previous pending iterator due to the asynchronous nature of signals and + // always moving to the end of the iterator before calling has_more. + while !self.signals.borrow_mut().handle.is_closed() { + if let Some(result) = self.iter.next() { + return PollResult::Signal(result); + } + + match self.signals.borrow_mut().poll_pending(has_signals) { + Ok(Some(pending)) => self.iter = pending, + Ok(None) => return PollResult::Pending, + Err(err) => return PollResult::Err(err), + } + } + + PollResult::Closed + } + + /// Get a shareable [`Handle`] for this instance. + /// + /// This can be used to add further signals or terminate the whole + /// signal iteration using the [`close`][Handle::close] method. + pub fn handle<R>(&self) -> Handle + where + SD: Borrow<SignalDelivery<R, E>>, + R: 'static + AsRawFd + Send + Sync, + { + self.signals.borrow().handle() + } +} + +/// A signal iterator which consumes a [`SignalDelivery`] instance and takes +/// ownership of it. +pub type OwningSignalIterator<R, E> = SignalIterator<SignalDelivery<R, E>, E>; + +/// A signal iterator which takes a mutable reference to a [`SignalDelivery`] +/// instance. +pub type RefSignalIterator<'a, R, E> = SignalIterator<&'a mut SignalDelivery<R, E>, E>; diff --git a/vendor/signal-hook/src/iterator/exfiltrator/mod.rs b/vendor/signal-hook/src/iterator/exfiltrator/mod.rs new file mode 100644 index 000000000..0b7cd0e34 --- /dev/null +++ b/vendor/signal-hook/src/iterator/exfiltrator/mod.rs @@ -0,0 +1,152 @@ +//! An abstraction over exfiltrating information out of signal handlers. +//! +//! The [`Exfiltrator`] trait provides a way to abstract the information extracted from a signal +//! handler and the way it is extracted out of it. +//! +//! The implementations can be used to parametrize the +//! [`SignalsInfo`][crate::iterator::SignalsInfo] to specify what results are returned. +//! +//! # Sealed +//! +//! Currently, the trait is sealed and all methods hidden. This is likely temporary, until some +//! experience with them is gained. + +#[cfg(feature = "extended-siginfo")] +#[cfg_attr(docsrs, doc(cfg(feature = "extended-siginfo")))] +pub mod origin; +pub mod raw; + +#[cfg(feature = "extended-siginfo")] +pub use origin::WithOrigin; +pub use raw::WithRawSiginfo; + +use std::sync::atomic::{AtomicBool, Ordering}; + +use libc::{c_int, siginfo_t}; + +mod sealed { + use std::fmt::Debug; + + use libc::{c_int, siginfo_t}; + + /// The actual implementation of the [`Exfiltrator`][super::Exfiltrator]. + /// + /// For now, this is hidden from the public API, but the intention is to move it to a public + /// place so users can implement it eventually, once we verify that it works well. + /// + /// # Safety + /// + /// The trait is unsafe as the [`Exfiltrator::store`] is called inside the signal handler and + /// must be async-signal-safe. Implementing this correctly may be difficult, therefore care + /// needs to be taken. One method known to work is encoding the data into an atomic variable. + /// Other, less limiting approaches, will be eventually explored. + pub unsafe trait Exfiltrator: Debug + Send + Sync + 'static { + /// One slot for storing the data. + /// + /// Each signal will get its one slot of this type, independent of other signals. It can + /// store the information in there inside the signal handler and will be loaded from it in + /// load. + /// + /// Each slot is initialized to the [`Default`] value. It is expected this value represents + /// „no signal delivered“ state. + type Storage: Debug + Default + Send + Sync + 'static; + + /// The type returned to the user. + type Output; + + /// If the given signal is supported by this specific exfiltrator. + /// + /// Not all information is available to all signals, therefore not all exfiltrators must + /// support all signals. If `false` is returned, the user is prevented for registering such + /// signal number with the given exfiltrator. + fn supports_signal(&self, sig: c_int) -> bool; + + /// Puts the signal information inside the slot. + /// + /// It needs to somehow store the relevant information and the fact that a signal happened. + /// + /// # Warning + /// + /// This will be called inside the signal handler. It needs to be async-signal-safe. In + /// particular, very small amount of operations are allowed in there. This namely does + /// *not* include any locking nor allocation. + /// + /// It is also possible that multiple store methods are called concurrently; it is up to + /// the implementor to deal with that. + fn store(&self, slot: &Self::Storage, signal: c_int, info: &siginfo_t); + + /// Loads the signal information from the given slot. + /// + /// The method shall check if the signal happened (it may be possible to be called without + /// the signal previously being delivered; it is up to the implementer to recognize it). It + /// is assumed the [`Default`] value is recognized as no signal delivered. + /// + /// If it was delivered, the method shall extract the relevant information *and reset the + /// slot* to the no signal delivered state. + /// + /// It shall return `Some(value)` if the signal was successfully received and `None` in + /// case no signal was delivered. + /// + /// No blocking shall happen inside this method. It may be called concurrently with + /// [`store`][Exfiltrator::store] (due to how signals work, concurrently even inside the + /// same thread ‒ a `store` may „interrupt“ a call to `load`). It is up to the implementer + /// to deal with that. + fn load(&self, slot: &Self::Storage, signal: c_int) -> Option<Self::Output>; + + /// Initialize the given slot for the given signal before the first use. + /// + /// This is called before the first use of the given slot (and it is annotated with the + /// corresponding signal). The default does nothing, this is just an opportunity to + /// allocate data lazily (this is called outside of the signal handler, so it doesn't have + /// to be async-signal-safe). It will be called at most once for each slot. + /// + /// Note that you can rely on this being called for correctness, but not for safety (this + /// crate calls it before the first use, but a user abusing the trait might not and in such + /// case it is OK to eg. lose signals, but not segfault). + fn init(&self, slot: &Self::Storage, signal: c_int) { + // Suppress unused variable warning without putting the underscores into public + // signature. + let _ = slot; + let _ = signal; + } + } +} + +/// A trait describing what and how is extracted from signal handlers. +/// +/// By choosing a specific implementor as the type parameter for +/// [`SignalsInfo`][crate::iterator::SignalsInfo], one can pick how much and what information is +/// returned from the iterator. +pub trait Exfiltrator: sealed::Exfiltrator {} + +impl<E: sealed::Exfiltrator> Exfiltrator for E {} + +/// An [`Exfiltrator`] providing just the signal numbers. +/// +/// This is the basic exfiltrator for most needs. For that reason, there's the +/// [`crate::iterator::Signals`] type alias, to simplify the type names for usual needs. +#[derive(Clone, Copy, Debug, Default)] +pub struct SignalOnly; + +unsafe impl sealed::Exfiltrator for SignalOnly { + type Storage = AtomicBool; + fn supports_signal(&self, _: c_int) -> bool { + true + } + type Output = c_int; + + fn store(&self, slot: &Self::Storage, _: c_int, _: &siginfo_t) { + slot.store(true, Ordering::SeqCst); + } + + fn load(&self, slot: &Self::Storage, signal: c_int) -> Option<Self::Output> { + if slot + .compare_exchange(true, false, Ordering::SeqCst, Ordering::Relaxed) + .is_ok() + { + Some(signal) + } else { + None + } + } +} diff --git a/vendor/signal-hook/src/iterator/exfiltrator/origin.rs b/vendor/signal-hook/src/iterator/exfiltrator/origin.rs new file mode 100644 index 000000000..c3e2f15d2 --- /dev/null +++ b/vendor/signal-hook/src/iterator/exfiltrator/origin.rs @@ -0,0 +1,66 @@ +//! An exfiltrator providing the process that caused the signal. +//! +//! The [`WithOrigin`] is an [`Exfiltrator`][crate::iterator::exfiltrator::Exfiltrator] that +//! provides the information about sending process in addition to the signal number, through the +//! [`Origin`] type. +//! +//! See the [`WithOrigin`] example. + +use libc::{c_int, siginfo_t}; + +pub use super::raw::Slot; +use super::sealed::Exfiltrator; +use super::WithRawSiginfo; +pub use crate::low_level::siginfo::{Origin, Process}; + +/// The [`Exfiltrator`][crate::iterator::exfiltrator::Exfiltrator] that produces [`Origin`] of +/// signals. +/// +/// # Examples +/// +/// ```rust +/// # use signal_hook::consts::SIGUSR1; +/// # use signal_hook::iterator::SignalsInfo; +/// # use signal_hook::iterator::exfiltrator::WithOrigin; +/// # +/// # fn main() -> Result<(), std::io::Error> { +/// // Subscribe to SIGUSR1, with information about the process. +/// let mut signals = SignalsInfo::<WithOrigin>::new(&[SIGUSR1])?; +/// +/// // Send a signal to ourselves. +/// let my_pid = unsafe { libc::getpid() }; +/// unsafe { libc::kill(my_pid, SIGUSR1) }; +/// +/// // Grab the signal and look into the details. +/// let received = signals.wait().next().unwrap(); +/// +/// assert_eq!(SIGUSR1, received.signal); +/// assert_eq!(my_pid, received.process.unwrap().pid); +/// # Ok(()) } +/// ``` +#[derive(Copy, Clone, Debug, Default)] +pub struct WithOrigin(WithRawSiginfo); + +// Safety: We need to be async-signal-safe. We delegate to other Exfiltrator, which already is and +// call a function that promises to be (Origin::extract) +unsafe impl Exfiltrator for WithOrigin { + type Storage = Slot; + type Output = Origin; + fn supports_signal(&self, signal: c_int) -> bool { + self.0.supports_signal(signal) + } + + fn store(&self, slot: &Slot, signal: c_int, info: &siginfo_t) { + self.0.store(slot, signal, info) + } + + fn load(&self, slot: &Self::Storage, signal: c_int) -> Option<Origin> { + self.0 + .load(slot, signal) + .map(|info| unsafe { Origin::extract(&info) }) + } + + fn init(&self, slot: &Self::Storage, signal: c_int) { + self.0.init(slot, signal) + } +} diff --git a/vendor/signal-hook/src/iterator/exfiltrator/raw.rs b/vendor/signal-hook/src/iterator/exfiltrator/raw.rs new file mode 100644 index 000000000..93c1ace6a --- /dev/null +++ b/vendor/signal-hook/src/iterator/exfiltrator/raw.rs @@ -0,0 +1,95 @@ +//! An exfiltrator providing the raw [`siginfo_t`]. + +// Note on unsafety in this module: +// * Implementing an unsafe trait, that one needs to ensure at least store is async-signal-safe. +// That's done by delegating to the Channel (and reading an atomic pointer, but that one is +// primitive op). +// * A bit of juggling with atomic and raw pointers. In effect, that is just late lazy +// initialization, the Slot is in line with Option would be, except that it is set atomically +// during the init. Lifetime is ensured by not dropping until the Drop of the whole slot and that +// is checked by taking `&mut self`. + +use std::sync::atomic::{AtomicPtr, Ordering}; + +use libc::{c_int, siginfo_t}; + +use super::sealed::Exfiltrator; +use crate::low_level::channel::Channel; + +#[doc(hidden)] +#[derive(Default, Debug)] +pub struct Slot(AtomicPtr<Channel<siginfo_t>>); + +impl Drop for Slot { + fn drop(&mut self) { + let ptr = self.0.load(Ordering::Acquire); + if !ptr.is_null() { + drop(unsafe { Box::from_raw(ptr) }); + } + } +} + +/// The [`Exfiltrator`][crate::iterator::exfiltrator::Exfiltrator] that produces the raw +/// [`libc::siginfo_t`]. Note that it might look differently on different OSes and its API is a +/// little bit more limited than its C counterpart. +/// +/// You might prefer the [`WithOrigin`][super::WithOrigin] if you simply need information about the +/// origin of the signal. +/// +/// # Examples +/// +/// ```rust +/// # use signal_hook::consts::SIGUSR1; +/// # use signal_hook::iterator::SignalsInfo; +/// # use signal_hook::iterator::exfiltrator::WithRawSiginfo; +/// # +/// # fn main() -> Result<(), std::io::Error> { +/// // Subscribe to SIGUSR1, with information about the process. +/// let mut signals = SignalsInfo::<WithRawSiginfo>::new(&[SIGUSR1])?; +/// +/// // Send ourselves a signal. +/// signal_hook::low_level::raise(SIGUSR1)?; +/// +/// // Grab the signal and look into the details. +/// let received = signals.wait().next().unwrap(); +/// +/// // Not much else is useful in a cross-platform way :-( +/// assert_eq!(SIGUSR1, received.si_signo); +/// # Ok(()) } +/// ``` +#[derive(Copy, Clone, Debug, Default)] +pub struct WithRawSiginfo; + +unsafe impl Exfiltrator for WithRawSiginfo { + type Storage = Slot; + type Output = siginfo_t; + + fn supports_signal(&self, _: c_int) -> bool { + true + } + + fn store(&self, slot: &Slot, _: c_int, info: &siginfo_t) { + let info = *info; + // Condition just not to crash if someone forgot to call init. + // + // Lifetime is from init to our own drop, and drop needs &mut self. + if let Some(slot) = unsafe { slot.0.load(Ordering::Acquire).as_ref() } { + slot.send(info); + } + } + + fn load(&self, slot: &Slot, _: libc::c_int) -> Option<siginfo_t> { + let slot = unsafe { slot.0.load(Ordering::Acquire).as_ref() }; + // Condition just not to crash if someone forgot to call init. + slot.and_then(|s| s.recv()) + } + + fn init(&self, slot: &Self::Storage, _: c_int) { + let new = Box::default(); + let old = slot.0.swap(Box::into_raw(new), Ordering::Release); + // We leak the pointer on purpose here. This is invalid state anyway and must not happen, + // but if it still does, we can't drop that while some other thread might still be having + // the raw pointer. + assert!(old.is_null(), "Init called multiple times"); + } +} diff --git a/vendor/signal-hook/src/iterator/mod.rs b/vendor/signal-hook/src/iterator/mod.rs new file mode 100644 index 000000000..b4bfec4e6 --- /dev/null +++ b/vendor/signal-hook/src/iterator/mod.rs @@ -0,0 +1,323 @@ +//! An iterator over incoming signals. +//! +//! This provides a higher abstraction over the signals, providing +//! the [`SignalsInfo`] structure which is able to iterate over the +//! incoming signals. The structure is parametrized by an +//! [`Exfiltrator`][self::exfiltrator::Exfiltrator], which specifies what information is returned +//! for each delivered signal. Note that some exfiltrators are behind a feature flag. +//! +//! The [`Signals`] is a type alias for the common case when it is enough to get the signal number. +//! +//! This module (and everything in it) is turned by the `iterator` feature. It is **on** by +//! default, the possibility to turn off is mostly possible for very special purposes (compiling on +//! `<rustc-1.36`, minimizing the amount of code compiled, …). In a sense, this is the highest +//! level abstraction of the crate and the API expected to be used by most of the people. +//! +//! # Examples +//! +//! ```rust +//! extern crate libc; +//! extern crate signal_hook; +//! +//! use std::io::Error; +//! +//! use signal_hook::consts::signal::*; +//! use signal_hook::iterator::Signals; +//! +//! fn main() -> Result<(), Error> { +//! let mut signals = Signals::new(&[ +//! SIGHUP, +//! SIGTERM, +//! SIGINT, +//! SIGQUIT, +//! # SIGUSR1, +//! ])?; +//! # // A trick to terminate the example when run as doc-test. Not part of the real code. +//! # signal_hook::low_level::raise(SIGUSR1).unwrap(); +//! 'outer: loop { +//! // Pick up signals that arrived since last time +//! for signal in signals.pending() { +//! match signal as libc::c_int { +//! SIGHUP => { +//! // Reload configuration +//! // Reopen the log file +//! } +//! SIGTERM | SIGINT | SIGQUIT => { +//! break 'outer; +//! }, +//! # 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(()) +//! } +//! ``` + +pub mod backend; +pub mod exfiltrator; + +use std::borrow::Borrow; +use std::fmt::{Debug, Formatter, Result as FmtResult}; +use std::io::{Error, ErrorKind, Read}; +use std::os::unix::net::UnixStream; + +use libc::{self, c_int}; + +pub use self::backend::{Handle, Pending}; +use self::backend::{PollResult, RefSignalIterator, SignalDelivery}; +use self::exfiltrator::{Exfiltrator, SignalOnly}; + +/// 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. +/// +/// Most users will want to use it through the [`Signals`] type alias for simplicity. +/// +/// # Multiple threads +/// +/// Instances of this struct can be [sent][std::marker::Send] to other threads. In a multithreaded +/// application this can be used to dedicate a separate thread for signal handling. In this case +/// you should get a [`Handle`] using the [`handle`][Signals::handle] method before sending the +/// `Signals` instance to a background thread. With the handle you will be able to shut down the +/// background thread later, or to operatively add more signals. +/// +/// The controller handle can be shared between as many threads as you like using its +/// [`clone`][Handle::clone] method. +/// +/// # Exfiltrators +/// +/// The [`SignalOnly]` provides only the signal number. There are further exfiltrators available in +/// the [`exfiltrator`] module. Note that some of them are behind feature flags that need to be +/// enabled. +/// +/// # Examples +/// +/// ```rust +/// # extern crate signal_hook; +/// # +/// # use std::io::Error; +/// # use std::thread; +/// use signal_hook::consts::signal::*; +/// use signal_hook::iterator::Signals; +/// +/// # +/// # fn main() -> Result<(), Error> { +/// let mut signals = Signals::new(&[SIGUSR1, SIGUSR2])?; +/// let handle = signals.handle(); +/// let thread = thread::spawn(move || { +/// for signal in &mut signals { +/// match signal { +/// SIGUSR1 => {}, +/// SIGUSR2 => {}, +/// _ => unreachable!(), +/// } +/// } +/// }); +/// +/// // Some time later... +/// handle.close(); +/// thread.join().unwrap(); +/// # Ok(()) +/// # } +/// ``` +pub struct SignalsInfo<E: Exfiltrator = SignalOnly>(SignalDelivery<UnixStream, E>); + +impl<E: Exfiltrator> SignalsInfo<E> { + /// Creates the `Signals` structure. + /// + /// This registers all the signals listed. The same restrictions (panics, errors) apply as + /// for the [`Handle::add_signal`] method. + pub fn new<I, S>(signals: I) -> Result<Self, Error> + where + I: IntoIterator<Item = S>, + S: Borrow<c_int>, + E: Default, + { + Self::with_exfiltrator(signals, E::default()) + } + + /// An advanced constructor with explicit [`Exfiltrator`]. + pub fn with_exfiltrator<I, S>(signals: I, exfiltrator: E) -> Result<Self, Error> + where + I: IntoIterator<Item = S>, + S: Borrow<c_int>, + { + let (read, write) = UnixStream::pair()?; + Ok(SignalsInfo(SignalDelivery::with_pipe( + read, + write, + exfiltrator, + signals, + )?)) + } + + /// Registers another signal to the set watched by this [`Signals`] instance. + /// + /// The same restrictions (panics, errors) apply as for the [`Handle::add_signal`] + /// method. + pub fn add_signal(&self, signal: c_int) -> Result<(), Error> { + self.handle().add_signal(signal) + } + + /// 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 instance may 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(&mut self) -> Pending<E> { + self.0.pending() + } + + /// Block until the stream contains some bytes. + /// + /// Returns true if it was possible to read a byte and false otherwise. + fn has_signals(read: &mut UnixStream) -> Result<bool, Error> { + loop { + match read.read(&mut [0u8]) { + Ok(num_read) => break Ok(num_read > 0), + // If we get an EINTR error it is fine to retry reading from the stream. + // Otherwise we should pass on the error to the caller. + Err(error) => { + if error.kind() != ErrorKind::Interrupted { + break Err(error); + } + } + } + } + } + + /// Waits for some signals to be available and returns an iterator. + /// + /// This is similar to [`pending`][SignalsInfo::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. If the [`Handle::close`] method is used in + /// another thread this method will return immediately. + /// + /// Note that the blocking is done in this method, not in the iterator. + pub fn wait(&mut self) -> Pending<E> { + match self.0.poll_pending(&mut Self::has_signals) { + Ok(Some(pending)) => pending, + // Because of the blocking has_signals method the poll_pending method + // only returns None if the instance is closed. But we want to return + // a possibly empty pending object anyway. + Ok(None) => self.pending(), + // Users can't manipulate the internal file descriptors and the way we use them + // shouldn't produce any errors. So it is OK to panic. + Err(error) => panic!("Unexpected error: {}", error), + } + } + + /// Is it closed? + /// + /// See [`close`][Handle::close]. + pub fn is_closed(&self) -> bool { + self.handle().is_closed() + } + + /// Get 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 `&mut Signals`. + /// + /// This iterator terminates only if explicitly [closed][Handle::close]. + /// + /// # Examples + /// + /// ```rust + /// # extern crate libc; + /// # extern crate signal_hook; + /// # + /// # use std::io::Error; + /// # use std::thread; + /// # + /// use signal_hook::consts::signal::*; + /// use signal_hook::iterator::Signals; + /// + /// # fn main() -> Result<(), Error> { + /// let mut signals = Signals::new(&[SIGUSR1, SIGUSR2])?; + /// let handle = signals.handle(); + /// thread::spawn(move || { + /// for signal in signals.forever() { + /// match signal { + /// SIGUSR1 => {}, + /// SIGUSR2 => {}, + /// _ => unreachable!(), + /// } + /// } + /// }); + /// handle.close(); + /// # Ok(()) + /// # } + /// ``` + pub fn forever(&mut self) -> Forever<E> { + Forever(RefSignalIterator::new(&mut self.0)) + } + + /// Get a shareable handle to a [`Handle`] for this instance. + /// + /// This can be used to add further signals or close the [`Signals`] instance. + pub fn handle(&self) -> Handle { + self.0.handle() + } +} + +impl<E> Debug for SignalsInfo<E> +where + E: Debug + Exfiltrator, + E::Storage: Debug, +{ + fn fmt(&self, fmt: &mut Formatter) -> FmtResult { + fmt.debug_tuple("Signals").field(&self.0).finish() + } +} + +impl<'a, E: Exfiltrator> IntoIterator for &'a mut SignalsInfo<E> { + type Item = E::Output; + type IntoIter = Forever<'a, E>; + fn into_iter(self) -> Self::IntoIter { + self.forever() + } +} + +/// An infinit iterator of arriving signals. +pub struct Forever<'a, E: Exfiltrator>(RefSignalIterator<'a, UnixStream, E>); + +impl<'a, E: Exfiltrator> Iterator for Forever<'a, E> { + type Item = E::Output; + + fn next(&mut self) -> Option<E::Output> { + match self.0.poll_signal(&mut SignalsInfo::<E>::has_signals) { + PollResult::Signal(result) => Some(result), + PollResult::Closed => None, + PollResult::Pending => unreachable!( + "Because of the blocking has_signals method the \ + poll_signal method never returns Poll::Pending but blocks until a signal arrived" + ), + // Users can't manipulate the internal file descriptors and the way we use them + // shouldn't produce any errors. So it is OK to panic. + PollResult::Err(error) => panic!("Unexpected error: {}", error), + } + } +} + +/// A type alias for an iterator returning just the signal numbers. +/// +/// This is the simplified version for most of the use cases. For advanced usages, the +/// [`SignalsInfo`] with explicit [`Exfiltrator`] type can be used. +pub type Signals = SignalsInfo<SignalOnly>; diff --git a/vendor/signal-hook/src/lib.rs b/vendor/signal-hook/src/lib.rs new file mode 100644 index 000000000..d750e15c2 --- /dev/null +++ b/vendor/signal-hook/src/lib.rs @@ -0,0 +1,414 @@ +#![doc( + test(attr(deny(warnings))), + test(attr(allow(bare_trait_objects, unknown_lints))) +)] +#![warn(missing_docs)] +// Don't fail on links to things not enabled in features +#![allow( + unknown_lints, + renamed_and_removed_lints, + intra_doc_link_resolution_failure, + broken_intra_doc_links +)] +// These little nifty labels saying that something needs a feature to be enabled +#![cfg_attr(docsrs, feature(doc_cfg))] +//! 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 +//! disrupting 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. +//! +//! # The goal of the library +//! +//! The aim is to subscriptions to signals a „structured“ resource, in a similar way memory +//! allocation is ‒ parts of the program can independently subscribe and it's the same part of the +//! program that can give them up, independently of what the other parts do. Therefore, it is +//! possible to register multiple actions to the same signal. +//! +//! Another goal is to shield applications away from differences between platforms. Various Unix +//! systems have little quirks and differences that need to be worked around and that's not +//! something every application should be dealing with. We even try to provide some support for +//! Windows, but we lack the expertise in that area, so that one is not complete and is a bit rough +//! (if you know how it works there and are willing to either contribute the code or consult, +//! please get in touch). +//! +//! Furthermore, it provides implementation of certain common signal-handling patterns, usable from +//! safe Rust, without the application author needing to learn about *all* the traps. +//! +//! Note that despite everything, there are still some quirks around signal handling that are not +//! possible to paper over and need to be considered. Also, there are some signal use cases that +//! are inherently unsafe and they are not covered by this crate. +//! +//! # Anatomy of the crate +//! +//! The crate is split into several modules. +//! +//! The easiest way to handle signals is using the [`Signals`][crate::iterator::Signals] iterator +//! thing. It can register for a set of signals and produce them one by one, in a blocking manner. +//! You can reserve a thread for handling them as they come. If you want something asynchronous, +//! there are adaptor crates for the most common asynchronous runtimes. The module also contains +//! ways to build iterators that produce a bit more information that just the signal number. +//! +//! The [`flag`] module contains routines to set a flag based on incoming signals and to do +//! certain actions inside the signal handlers based on the flags (the flags can also be +//! manipulated by the rest of the application). This allows building things like checking if a +//! signal happened on each loop iteration or making sure application shuts down on the second +//! CTRL+C if it got stuck in graceful shutdown requested by the first. +//! +//! The [`consts`] module contains some constants, most importantly the signal numbers themselves +//! (these are just re-exports from [`libc`] and if your OS has some extra ones, you can use them +//! too, this is just for convenience). +//! +//! And last, there is the [`low_level`] module. It contains routines to directly register and +//! unregister arbitrary actions. Some of the patters in the above modules return a [`SigId`], +//! which can be used with the [`low_level::unregister`] to remove the action. There are also some +//! other utilities that are more suited to build other abstractions with than to use directly. +//! +//! Certain parts of the library can be enabled or disabled with use flags: +//! +//! * `channel`: The [low_level::channel] module (on by default). +//! * `iterator`: The [iterator] module (on by default). +//! * `extended-sig-info`: Support for providing more information in the iterators or from the +//! async adaptor crates. This is off by default. +//! +//! # Limitations +//! +//! * OS limitations still apply. Certain signals are not possible to override or subscribe to ‒ +//! `SIGKILL` or `SIGSTOP`. +//! * Overriding some others is probably a very stupid idea (or very unusual needs) ‒ handling eg. +//! `SIGSEGV` is not something done lightly. For that reason, the crate will panic in case +//! registering of these is attempted (see [`FORBIDDEN`][crate::consts::FORBIDDEN]. If you still +//! need to do so, you can find such APIs in the `signal-hook-registry` backend crate, but +//! additional care must be taken. +//! * Interaction with other signal-handling libraries is limited. If signal-hook finds an existing +//! handler present, it chain-calls it from the signal it installs and assumes other libraries +//! would do the same, but that's everything that can be done to make it work with libraries not +//! based on [`signal-hook-registry`](https://lib.rs/signal-hook-registry) +//! (the backend of this crate). +//! * The above chaining contains a race condition in multi-threaded programs, where the previous +//! handler might not get called if it is received during the registration process. This is +//! handled (at least on non-windows platforms) on the same thread where the registration +//! happens, therefore it is advised to register at least one action for each signal of interest +//! early, before any additional threads are started. Registering any additional (or removing and +//! registering again) action on the same signal is without the race condition. +//! * Once at least one action is registered for a signal, the default action is replaced (this is +//! how signals work in the OS). Even if all actions of that signal are removed, `signal-hook` +//! does not restore the default handler (such behaviour would be at times inconsistent with +//! making the actions independent and there's no reasonable way to do so in a race-free way in a +//! multi-threaded program while also dealing with signal handlers registered with other +//! libraries). It is, however, possible to *emulate* the default handler (see the +//! [`emulate_default_handler`][low_level::emulate_default_handler]) ‒ there are only 4 +//! default handlers: +//! - Ignore. This is easy to emulate. +//! - Abort. Depending on if you call it from within a signal handler of from outside, the +//! [`low_level::abort`] or [`std::process::abort`] can be used. +//! - Terminate. This can be done with `exit` ([`low_level::exit`] or [`std::process::exit`]). +//! - Stop. It is possible to [`raise`][low_level::raise] the [`SIGSTOP`][consts::SIGSTOP] signal. +//! That one can't be replaced and always stops the application. +//! * Many of the patterns here can collate multiple instances of the same signal into fewer +//! instances, if the application doesn't consume them fast enough. This is consistent with what +//! the kernel does if the application doesn't keep up with them (at least for non-realtime +//! signals, see below), so it is something one needs to deal with anyway. +//! * (By design) the library mostly _postpones_ or helps the user postpone acting on the signals +//! until later. This, in combination with the above collating inside the library may make it +//! unsuitable for realtime signals. These usually want to be handled directly inside the signal +//! handler ‒ which still can be done with [signal_hook_registry::register], but using unsafe and +//! due care. Patterns for working safely with realtime signals are not unwanted in the library, +//! but nobody contributed them yet. +//! +//! # 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://lib.rs/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. +//! +//! Non-standard signals are also supported. Pass the signal value directly from `libc` or use +//! the numeric value directly. +//! +//! ```rust +//! use std::sync::Arc; +//! use std::sync::atomic::{AtomicBool}; +//! let term = Arc::new(AtomicBool::new(false)); +//! let _ = signal_hook::flag::register(libc::SIGINT, Arc::clone(&term)); +//! ``` +//! +//! This crate includes a limited support for Windows, based on `signal`/`raise` in the CRT. +//! There are differences in both API and behavior: +//! +//! - Many parts of the library are not available there. +//! - 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. +//! +//! # Features +//! +//! There are several feature flags that control how much is available as part of the crate, some +//! enabled by default. +//! +//! * `channel`: (enabled by default) The [Channel][crate::low_level::channel] synchronization +//! primitive for exporting data out of signal handlers. +//! * `iterator`: (enabled by default) An [Signals iterator][crate::iterator::Signals] that +//! provides a convenient interface for receiving signals in rust-friendly way. +//! * `extended-siginfo` adds support for providing extra information as part of the iterator +//! interface. +//! +//! # Examples +//! +//! ## Using a flag to terminate a loop-based application +//! +//! ```rust +//! 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::consts::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(()) +//! } +//! ``` +//! +//! ## A complex signal handling with a background thread +//! +//! This also handles the double CTRL+C situation (eg. the second CTRL+C kills) and resetting the +//! terminal on `SIGTSTP` (CTRL+Z, curses-based applications should do something like this). +//! +//! ```rust +//! # #[cfg(feature = "extended-siginfo")] pub mod test { +//! use std::io::Error; +//! use std::sync::Arc; +//! use std::sync::atomic::AtomicBool; +//! +//! use signal_hook::consts::signal::*; +//! use signal_hook::consts::TERM_SIGNALS; +//! use signal_hook::flag; +//! // A friend of the Signals iterator, but can be customized by what we want yielded about each +//! // signal. +//! use signal_hook::iterator::SignalsInfo; +//! use signal_hook::iterator::exfiltrator::WithOrigin; +//! use signal_hook::low_level; +//! +//! # struct App; +//! # impl App { +//! # fn run_background() -> Self { Self } +//! # fn wait_for_stop(self) {} +//! # fn restore_term(&self) {} +//! # fn claim_term(&self) {} +//! # fn resize_term(&self) {} +//! # fn reload_config(&self) {} +//! # fn print_stats(&self) {} +//! # } +//! # pub +//! fn main() -> Result<(), Error> { +//! // Make sure double CTRL+C and similar kills +//! let term_now = Arc::new(AtomicBool::new(false)); +//! for sig in TERM_SIGNALS { +//! // When terminated by a second term signal, exit with exit code 1. +//! // This will do nothing the first time (because term_now is false). +//! flag::register_conditional_shutdown(*sig, 1, Arc::clone(&term_now))?; +//! // But this will "arm" the above for the second time, by setting it to true. +//! // The order of registering these is important, if you put this one first, it will +//! // first arm and then terminate ‒ all in the first round. +//! flag::register(*sig, Arc::clone(&term_now))?; +//! } +//! +//! // Subscribe to all these signals with information about where they come from. We use the +//! // extra info only for logging in this example (it is not available on all the OSes or at +//! // all the occasions anyway, it may return `Unknown`). +//! let mut sigs = vec![ +//! // Some terminal handling +//! SIGTSTP, SIGCONT, SIGWINCH, +//! // Reload of configuration for daemons ‒ um, is this example for a TUI app or a daemon +//! // O:-)? You choose... +//! SIGHUP, +//! // Application-specific action, to print some statistics. +//! SIGUSR1, +//! ]; +//! sigs.extend(TERM_SIGNALS); +//! let mut signals = SignalsInfo::<WithOrigin>::new(&sigs)?; +//! # low_level::raise(SIGTERM)?; // Trick to terminate the example +//! +//! // This is the actual application that'll start in its own thread. We'll control it from +//! // this thread based on the signals, but it keeps running. +//! // This is called after all the signals got registered, to avoid the short race condition +//! // in the first registration of each signal in multi-threaded programs. +//! let app = App::run_background(); +//! +//! // Consume all the incoming signals. This happens in "normal" Rust thread, not in the +//! // signal handlers. This means that we are allowed to do whatever we like in here, without +//! // restrictions, but it also means the kernel believes the signal already got delivered, we +//! // handle them in delayed manner. This is in contrast with eg the above +//! // `register_conditional_shutdown` where the shutdown happens *inside* the handler. +//! let mut has_terminal = true; +//! for info in &mut signals { +//! // Will print info about signal + where it comes from. +//! eprintln!("Received a signal {:?}", info); +//! match info.signal { +//! SIGTSTP => { +//! // Restore the terminal to non-TUI mode +//! if has_terminal { +//! app.restore_term(); +//! has_terminal = false; +//! // And actually stop ourselves. +//! low_level::emulate_default_handler(SIGTSTP)?; +//! } +//! } +//! SIGCONT => { +//! if !has_terminal { +//! app.claim_term(); +//! has_terminal = true; +//! } +//! } +//! SIGWINCH => app.resize_term(), +//! SIGHUP => app.reload_config(), +//! SIGUSR1 => app.print_stats(), +//! term_sig => { // These are all the ones left +//! eprintln!("Terminating"); +//! assert!(TERM_SIGNALS.contains(&term_sig)); +//! break; +//! } +//! } +//! } +//! +//! // If during this another termination signal comes, the trick at the top would kick in and +//! // terminate early. But if it doesn't, the application shuts down gracefully. +//! app.wait_for_stop(); +//! +//! Ok(()) +//! } +//! # } +//! # fn main() { +//! # #[cfg(feature = "extended-siginfo")] test::main().unwrap(); +//! # } +//! ``` +//! +//! # Asynchronous runtime support +//! +//! If you are looking for integration with an asynchronous runtime take a look at one of the +//! following adapter crates: +//! +//! * [`signal-hook-async-std`](https://docs.rs/signal-hook-async-std) for async-std support +//! * [`signal-hook-mio`](https://docs.rs/signal-hook-mio) for MIO support +//! * [`signal-hook-tokio`](https://docs.rs/signal-hook-tokio) for Tokio support +//! +//! Feel free to open a pull requests if you want to add support for runtimes not mentioned above. +//! +//! # Porting from previous versions +//! +//! There were some noisy changes when going from 0.2 version to the 0.3 version. In particular: +//! +//! * A lot of things moved around to make the structure of the crate a bit more understandable. +//! Most of the time it should be possible to just search the documentation for the name that +//! can't be resolved to discover the new location. +//! - The signal constants (`SIGTERM`, for example) are in [`consts`] submodule (individual +//! imports) and in the [`consts::signal`] (for wildcard import of all of them). +//! - Some APIs that are considered more of a low-level building blocks than for casual day to +//! day use are now in the [`low_level`] submodule. +//! * The previous version contained the `cleanup` module that allowed for removal of the actions +//! in rather destructive way (nuking actions of arbitrary other parts of the program). This is +//! completely gone in this version. The use case of shutting down the application on second +//! CTRL+C is now supported by a pattern described in the [`flag`] submodule. For other similar +//! needs, refer above for emulating default handlers. + +pub mod flag; +#[cfg(all(not(windows), feature = "iterator"))] +#[cfg_attr(docsrs, doc(cfg(all(not(windows), feature = "iterator"))))] +pub mod iterator; +pub mod low_level; + +/// The low-level constants. +/// +/// Like the signal numbers. +pub mod consts { + + use libc::c_int; + + /// The signal constants. + /// + /// Can be mass-imported by `use signal_hook::consts::signal::*`, without polluting the + /// namespace with other names. Also available in the [`consts`][crate::consts] directly (but + /// with more constants around). + pub mod signal { + #[cfg(not(windows))] + pub use libc::{ + SIGABRT, SIGALRM, SIGBUS, SIGCHLD, SIGCONT, SIGFPE, SIGHUP, SIGILL, SIGINT, SIGKILL, + SIGPIPE, SIGPROF, SIGQUIT, SIGSEGV, SIGSTOP, SIGSYS, SIGTERM, SIGTRAP, SIGTSTP, + SIGTTIN, SIGTTOU, SIGURG, SIGUSR1, SIGUSR2, SIGVTALRM, SIGWINCH, SIGXCPU, SIGXFSZ, + }; + + #[cfg(not(any(windows, target_os = "haiku")))] + pub use libc::SIGIO; + + #[cfg(any( + target_os = "freebsd", + target_os = "dragonfly", + target_os = "netbsd", + target_os = "openbsd", + target_os = "macos" + ))] + pub use libc::SIGINFO; + + #[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 self::signal::*; + + pub use signal_hook_registry::FORBIDDEN; + + /// Various signals commonly requesting shutdown of an application. + #[cfg(not(windows))] + pub const TERM_SIGNALS: &[c_int] = &[SIGTERM, SIGQUIT, SIGINT]; + + /// Various signals commonly requesting shutdown of an application. + #[cfg(windows)] + pub const TERM_SIGNALS: &[c_int] = &[SIGTERM, SIGINT]; +} + +pub use signal_hook_registry::SigId; diff --git a/vendor/signal-hook/src/low_level/channel.rs b/vendor/signal-hook/src/low_level/channel.rs new file mode 100644 index 000000000..cc46c836f --- /dev/null +++ b/vendor/signal-hook/src/low_level/channel.rs @@ -0,0 +1,235 @@ +//! A restricted channel to pass data from signal handler. +//! +//! When trying to communicate data from signal handler to the outside world, one can use an atomic +//! variable (as it doesn't lock, so it can be made async-signal-safe). But this won't work for +//! larger data. +//! +//! This module provides a channel that can be used for that purpose. It is used by certain +//! [exfiltrators][crate::iterator::exfiltrator], but can be used as building block for custom +//! actions. In general, this is not a ready-made end-user API. +//! +//! # How does it work +//! +//! Each channel has a fixed number of slots and two queues (one for empty slots, one for full +//! slots). A signal handler takes a slot out of the empty one, fills it and passes it into the +//! full one. Outside of signal handler, it can take the value out of the full queue and return the +//! slot to the empty queue. +//! +//! The queues are implemented as bit-encoded indexes of the slots in the storage. The bits are +//! stored in an atomic variable. +//! +//! Note that the algorithm allows for a slot to be in neither queue (when it is being emptied or +//! filled). +//! +//! # Fallible allocation of a slot +//! +//! It is apparent that allocation of a new slot can fail (there's nothing in the empty slot). In +//! such case, there's no way to send the new value out of the handler (there's no way to safely +//! wait for a slot to appear, because the handler can be blocking the thread that is responsible +//! for emptying them). But that's considered acceptable ‒ even the kernel collates the same kinds +//! of signals together if they are not consumed by application fast enough and there are no free +//! slots exactly because some are being filled, emptied or are full ‒ in particular, the whole +//! system will yield a signal. +//! +//! This assumes that separate signals don't share the same buffer and that there's only one reader +//! (using multiple readers is still safe, but it is possible that all slots would be inside the +//! readers, but already empty, so the above argument would not hold). + +// TODO: Other sizes? Does anyone need more than 5 slots? + +use std::cell::UnsafeCell; +use std::sync::atomic::{AtomicU16, Ordering}; + +const SLOTS: usize = 5; +const BITS: u16 = 3; +const MASK: u16 = 0b111; + +fn get(n: u16, idx: u16) -> u16 { + (n >> (BITS * idx)) & MASK +} + +fn set(n: u16, idx: u16, v: u16) -> u16 { + let v = v << (BITS * idx); + let mask = MASK << (BITS * idx); + (n & !mask) | v +} + +fn enqueue(q: &AtomicU16, val: u16) { + let mut current = q.load(Ordering::Relaxed); + loop { + let empty = (0..SLOTS as u16) + .find(|i| get(current, *i) == 0) + .expect("No empty slot available"); + let modified = set(current, empty, val); + match q.compare_exchange_weak(current, modified, Ordering::Release, Ordering::Relaxed) { + Ok(_) => break, + Err(changed) => current = changed, // And retry with the changed value + } + } +} + +fn dequeue(q: &AtomicU16) -> Option<u16> { + let mut current = q.load(Ordering::Relaxed); + loop { + let val = current & MASK; + // It's completely empty + if val == 0 { + break None; + } + let modified = current >> BITS; + match q.compare_exchange_weak(current, modified, Ordering::Acquire, Ordering::Relaxed) { + Ok(_) => break Some(val), + Err(changed) => current = changed, + } + } +} + +/// A restricted async-signal-safe channel +/// +/// This is a bit like the usual channel used for inter-thread communication, but with several +/// restrictions: +/// +/// * There's a limited number of slots (currently 5). +/// * There's no way to wait for a place in it or for a value. If value is not available, `None` is +/// returned. If there's no space for a value, the value is silently dropped. +/// +/// In exchange for that, all the operations on that channel are async-signal-safe. That means it +/// is possible to use it to communicate between a signal handler and the rest of the world with it +/// (specifically, it's designed to send information from the handler to the rest of the +/// application). The throwing out of values when full is in line with collating of the same type +/// in kernel (you should not use the same channel for multiple different signals). +/// +/// Technically, this is a MPMC queue which preserves order, but it is expected to be used in MPSC +/// mode mostly (in theory, multiple threads can be executing a signal handler for the same signal +/// at the same time). The channel is not responsible for wakeups. +/// +/// While the channel is async-signal-safe, you still need to make sure *creating* of the values is +/// too (it should not contain anything that allocates, for example ‒ so no `String`s inside, etc). +/// +/// The code was *not* tuned for performance (signals are not expected to happen often). +pub struct Channel<T> { + storage: [UnsafeCell<Option<T>>; SLOTS], + empty: AtomicU16, + full: AtomicU16, +} + +impl<T> Channel<T> { + /// Creates a new channel with nothing in it. + pub fn new() -> Self { + let storage = Default::default(); + let me = Self { + storage, + empty: AtomicU16::new(0), + full: AtomicU16::new(0), + }; + + for i in 1..SLOTS + 1 { + enqueue(&me.empty, i as u16); + } + + me + } + + /// Inserts a value into the channel. + /// + /// If the value doesn't fit, it is silently dropped. Never blocks. + pub fn send(&self, val: T) { + if let Some(empty_idx) = dequeue(&self.empty) { + unsafe { *self.storage[empty_idx as usize - 1].get() = Some(val) }; + enqueue(&self.full, empty_idx); + } + } + + /// Takes a value from the channel. + /// + /// Or returns `None` if the channel is empty. Never blocks. + pub fn recv(&self) -> Option<T> { + dequeue(&self.full).map(|idx| { + let result = unsafe { &mut *self.storage[idx as usize - 1].get() } + .take() + .expect("Full slot with nothing in it"); + enqueue(&self.empty, idx); + result + }) + } +} + +impl<T> Default for Channel<T> { + fn default() -> Self { + Self::new() + } +} + +unsafe impl<T: Send> Send for Channel<T> {} + +// Yes, really Send -> Sync. Having a reference to Channel allows Sending Ts, but not having refs +// on them. +unsafe impl<T: Send> Sync for Channel<T> {} + +#[cfg(test)] +mod tests { + use std::sync::Arc; + use std::thread; + + use super::*; + + #[test] + fn new_empty() { + let channel = Channel::<usize>::new(); + assert!(channel.recv().is_none()); + assert!(channel.recv().is_none()); + } + + #[test] + fn pass_value() { + let channel = Channel::new(); + channel.send(42); + assert_eq!(42, channel.recv().unwrap()); + assert!(channel.recv().is_none()); + } + + #[test] + fn multiple() { + let channel = Channel::new(); + for i in 0..1000 { + channel.send(i); + assert_eq!(i, channel.recv().unwrap()); + assert!(channel.recv().is_none()); + } + } + + #[test] + fn overflow() { + let channel = Channel::new(); + for i in 0..10 { + channel.send(i); + } + for i in 0..5 { + assert_eq!(i, channel.recv().unwrap()); + } + assert!(channel.recv().is_none()); + } + + #[test] + fn multi_thread() { + let channel = Arc::new(Channel::<usize>::new()); + + let sender = thread::spawn({ + let channel = Arc::clone(&channel); + move || { + for i in 0..4 { + channel.send(i); + } + } + }); + + let mut results = Vec::new(); + while results.len() < 4 { + results.extend(channel.recv()); + } + + assert_eq!(vec![0, 1, 2, 3], results); + + sender.join().unwrap(); + } +} diff --git a/vendor/signal-hook/src/low_level/extract.c b/vendor/signal-hook/src/low_level/extract.c new file mode 100644 index 000000000..5f226158b --- /dev/null +++ b/vendor/signal-hook/src/low_level/extract.c @@ -0,0 +1,55 @@ +/* + * Low-level extraction code to overcome rust's libc not having the best access + * to siginfo_t details. + */ +#include <stdbool.h> +#include <signal.h> +#include <stdint.h> + +struct Const { + int native; + // The signal this applies to, or -1 if it applies to anything. + int signal; + uint8_t translated; +}; + +// Warning: must be in sync with the rust source code +struct Const consts[] = { +#ifdef SI_KERNEL + { SI_KERNEL, -1, 1 }, +#endif + { SI_USER, -1, 2 }, +#ifdef SI_TKILL + { SI_TKILL, -1, 3 }, +#endif + { SI_QUEUE, -1, 4 }, + { SI_MESGQ, -1, 5 }, + { CLD_EXITED, SIGCHLD, 6 }, + { CLD_KILLED, SIGCHLD, 7 }, + { CLD_DUMPED, SIGCHLD, 8 }, + { CLD_TRAPPED, SIGCHLD, 9 }, + { CLD_STOPPED, SIGCHLD, 10 }, + { CLD_CONTINUED, SIGCHLD, 11 }, +}; + +uint8_t sighook_signal_cause(const siginfo_t *info) { + const size_t const_len = sizeof consts / sizeof *consts; + size_t i; + for (i = 0; i < const_len; i ++) { + if ( + consts[i].native == info->si_code && + (consts[i].signal == -1 || consts[i].signal == info->si_signo) + ) { + return consts[i].translated; + } + } + return 0; // The "Unknown" variant +} + +pid_t sighook_signal_pid(const siginfo_t *info) { + return info->si_pid; +} + +uid_t sighook_signal_uid(const siginfo_t *info) { + return info->si_uid; +} diff --git a/vendor/signal-hook/src/low_level/mod.rs b/vendor/signal-hook/src/low_level/mod.rs new file mode 100644 index 000000000..bf99fac78 --- /dev/null +++ b/vendor/signal-hook/src/low_level/mod.rs @@ -0,0 +1,59 @@ +//! Some low level utilities +//! +//! More often to build other abstractions than used directly. + +use std::io::Error; + +use libc::c_int; + +#[cfg(feature = "channel")] +#[cfg_attr(docsrs, doc(cfg(feature = "channel")))] +pub mod channel; +#[cfg(not(windows))] +#[cfg_attr(docsrs, doc(cfg(not(windows))))] +pub mod pipe; +#[cfg(feature = "extended-siginfo-raw")] +#[cfg_attr(docsrs, doc(cfg(feature = "extended-siginfo-raw")))] +pub mod siginfo; +mod signal_details; + +pub use signal_hook_registry::{register, unregister}; + +pub use self::signal_details::{emulate_default_handler, signal_name}; + +/// The usual raise, just the safe wrapper around it. +/// +/// This is async-signal-safe. +pub fn raise(sig: c_int) -> Result<(), Error> { + let result = unsafe { libc::raise(sig) }; + if result == -1 { + Err(Error::last_os_error()) + } else { + Ok(()) + } +} + +/// A bare libc abort. +/// +/// Unlike the [std::process::abort], this one is guaranteed to contain no additions or wrappers +/// and therefore is async-signal-safe. You can use this to terminate the application from within a +/// signal handler. +pub fn abort() -> ! { + unsafe { + libc::abort(); + } +} + +/// A bare libc exit. +/// +/// Unlike the [std::process::exit], this one is guaranteed to contain no additions or wrappers and +/// therefore is async-signal-safe. You can use this to terminate the application from within a +/// signal handler. +/// +/// Also, see [`register_conditional_shutdown`][crate::flag::register_conditional_shutdown]. +pub fn exit(status: c_int) -> ! { + unsafe { + // Yes, the one with underscore. That one doesn't call the at-exit hooks. + libc::_exit(status); + } +} diff --git a/vendor/signal-hook/src/low_level/pipe.rs b/vendor/signal-hook/src/low_level/pipe.rs new file mode 100644 index 000000000..3cd218743 --- /dev/null +++ b/vendor/signal-hook/src/low_level/pipe.rs @@ -0,0 +1,265 @@ +//! 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`][crate::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 [`SignalsInfo`][crate::iterator::SignalsInfo] +//! 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 +//! use std::io::{Error, Read}; +//! use std::os::unix::net::UnixStream; +//! +//! use signal_hook::consts::SIGUSR1; +//! use signal_hook::low_level::{pipe, raise}; +//! +//! fn main() -> Result<(), Error> { +//! let (mut read, write) = UnixStream::pair()?; +//! pipe::register(SIGUSR1, write)?; +//! // This will write into the pipe write end through the signal handler +//! raise(SIGUSR1).unwrap(); +//! let mut buff = [0]; +//! read.read_exact(&mut buff)?; +//! println!("Happily terminating"); +//! Ok(()) +//! } + +use std::io::{Error, ErrorKind}; +use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd}; + +use libc::{self, c_int}; + +use crate::SigId; + +#[cfg(target_os = "aix")] +const MSG_NOWAIT: i32 = libc::MSG_NONBLOCK; +#[cfg(not(target_os = "aix"))] +const MSG_NOWAIT: i32 = libc::MSG_DONTWAIT; + +#[derive(Copy, Clone)] +pub(crate) enum WakeMethod { + Send, + Write, +} + +struct WakeFd { + fd: RawFd, + method: WakeMethod, +} + +impl WakeFd { + /// 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(()) + } + fn wake(&self) { + wake(self.fd, self.method); + } +} + +impl AsRawFd for WakeFd { + fn as_raw_fd(&self) -> RawFd { + self.fd + } +} + +impl Drop for WakeFd { + fn drop(&mut self) { + unsafe { + libc::close(self.fd); + } + } +} + +pub(crate) fn wake(pipe: RawFd, method: WakeMethod) { + 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. + let data = b"X" as *const _ as *const _; + match method { + WakeMethod::Write => libc::write(pipe, data, 1), + WakeMethod::Send => libc::send(pipe, data, 1, MSG_NOWAIT), + }; + } +} + +/// Registers a write to a self-pipe whenever there's the signal. +/// +/// In this case, the pipe is taken as the `RawFd`. It'll be closed on deregistration. Effectively, +/// the function takes ownership of the file descriptor. This includes feeling free to set arbitrary +/// flags on it, including file status flags (that are shared across file descriptors created by +/// `dup`). +/// +/// Note that passing the wrong file descriptor won't cause UB, but can still lead to severe bugs ‒ +/// like data corruptions in files. Prefer using [`register`] if possible. +/// +/// Also, it is perfectly legal for multiple writes to be collated together (if not consumed) and +/// to generate spurious wakeups (but will not generate spurious *bytes* in the pipe). +/// +/// # Internal details +/// +/// Internally, it *currently* does following. Note that this is *not* part of the stability +/// guarantees and may change if necessary. +/// +/// * If the file descriptor can be used with [`send`][libc::send], it'll be used together with +/// [`MSG_DONTWAIT`][libc::MSG_DONTWAIT]. This is tested by sending `0` bytes of data (depending +/// on the socket type, this might wake the read end with an empty message). +/// * If it is not possible, the [`O_NONBLOCK`][libc::O_NONBLOCK] will be set on the file +/// descriptor and [`write`][libc::write] will be used instead. +pub fn register_raw(signal: c_int, pipe: RawFd) -> Result<SigId, Error> { + let res = unsafe { libc::send(pipe, &[] as *const _, 0, MSG_NOWAIT) }; + let fd = match (res, Error::last_os_error().kind()) { + (0, _) | (-1, ErrorKind::WouldBlock) => WakeFd { + fd: pipe, + method: WakeMethod::Send, + }, + _ => { + let fd = WakeFd { + fd: pipe, + method: WakeMethod::Write, + }; + fd.set_flags()?; + fd + } + }; + let action = move || fd.wake(); + unsafe { super::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. +/// +/// See [`register_raw`] for further details. +pub fn register<P>(signal: c_int, pipe: P) -> Result<SigId, Error> +where + P: IntoRawFd + 'static, +{ + register_raw(signal, pipe.into_raw_fd()) +} + +#[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() { + crate::low_level::raise(libc::SIGUSR1).unwrap(); + } + + #[test] + fn register_with_socket() -> Result<(), Error> { + let (mut read, write) = UnixStream::pair()?; + register(libc::SIGUSR1, write)?; + wakeup(); + let mut buff = [0; 1]; + read.read_exact(&mut buff)?; + assert_eq!(b"X", &buff); + Ok(()) + } + + #[test] + #[cfg(not(target_os = "haiku"))] + fn register_dgram_socket() -> Result<(), Error> { + let (read, write) = UnixDatagram::pair()?; + register(libc::SIGUSR1, write)?; + wakeup(); + let mut buff = [0; 1]; + // The attempt to detect if it is socket can generate an empty message. Therefore, do a few + // retries. + for _ in 0..3 { + let len = read.recv(&mut buff)?; + if len == 1 && &buff == b"X" { + return Ok(()); + } + } + panic!("Haven't received the right data"); + } + + #[test] + fn register_with_pipe() -> Result<(), Error> { + let mut fds = [0; 2]; + unsafe { assert_eq!(0, libc::pipe(fds.as_mut_ptr())) }; + register_raw(libc::SIGUSR1, fds[1])?; + wakeup(); + let mut buff = [0; 1]; + unsafe { assert_eq!(1, libc::read(fds[0], buff.as_mut_ptr() as *mut _, 1)) } + assert_eq!(b"X", &buff); + Ok(()) + } +} diff --git a/vendor/signal-hook/src/low_level/siginfo.rs b/vendor/signal-hook/src/low_level/siginfo.rs new file mode 100644 index 000000000..9114d7f79 --- /dev/null +++ b/vendor/signal-hook/src/low_level/siginfo.rs @@ -0,0 +1,261 @@ +//! Extracting more information from the C [`siginfo_t`] structure. +//! +//! See [`Origin`]. + +use std::fmt::{Debug, Formatter, Result as FmtResult}; + +use libc::{c_int, pid_t, siginfo_t, uid_t}; + +use crate::low_level; + +// Careful: make sure the signature and the constants match the C source +extern "C" { + fn sighook_signal_cause(info: &siginfo_t) -> ICause; + fn sighook_signal_pid(info: &siginfo_t) -> pid_t; + fn sighook_signal_uid(info: &siginfo_t) -> uid_t; +} + +// Warning: must be in sync with the C code +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[non_exhaustive] +#[repr(u8)] +// For some reason, the fact it comes from the C makes rustc emit warning that *some* of these are +// not constructed. No idea why only some of them. +#[allow(dead_code)] +enum ICause { + Unknown = 0, + Kernel = 1, + User = 2, + TKill = 3, + Queue = 4, + MesgQ = 5, + Exited = 6, + Killed = 7, + Dumped = 8, + Trapped = 9, + Stopped = 10, + Continued = 11, +} + +impl ICause { + // The MacOs doesn't use the SI_* constants and leaves si_code at 0. But it doesn't use an + // union, it has a good-behaved struct with fields and therefore we *can* read the values, + // even though they'd contain nonsense (zeroes). We wipe that out later. + #[cfg(target_os = "macos")] + fn has_process(self) -> bool { + true + } + + #[cfg(not(target_os = "macos"))] + fn has_process(self) -> bool { + use ICause::*; + match self { + Unknown | Kernel => false, + User | TKill | Queue | MesgQ | Exited | Killed | Dumped | Trapped | Stopped + | Continued => true, + } + } +} + +/// Information about process, as presented in the signal metadata. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[non_exhaustive] +pub struct Process { + /// The process ID. + pub pid: pid_t, + + /// The user owning the process. + pub uid: uid_t, +} + +impl Process { + /** + * Extract the process information. + * + * # Safety + * + * The `info` must have a `si_code` corresponding to some situation that has the `si_pid` + * and `si_uid` filled in. + */ + unsafe fn extract(info: &siginfo_t) -> Self { + Self { + pid: sighook_signal_pid(info), + uid: sighook_signal_uid(info), + } + } +} + +/// The means by which a signal was sent by other process. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[non_exhaustive] +pub enum Sent { + /// The `kill` call. + User, + + /// The `tkill` call. + /// + /// This is likely linux specific. + TKill, + + /// `sigqueue`. + Queue, + + /// `mq_notify`. + MesgQ, +} + +/// A child changed its state. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[non_exhaustive] +pub enum Chld { + /// The child exited normally. + Exited, + + /// It got killed by a signal. + Killed, + + /// It got killed by a signal and dumped core. + Dumped, + + /// The child was trapped by a `SIGTRAP` signal. + Trapped, + + /// The child got stopped. + Stopped, + + /// The child continued (after being stopped). + Continued, +} + +/// What caused a signal. +/// +/// This is a best-effort (and possibly incomplete) representation of the C `siginfo_t::si_code`. +/// It may differ between OSes and may be extended in future versions. +/// +/// Note that this doesn't contain all the „fault“ signals (`SIGILL`, `SIGSEGV` and similar). +/// There's no reasonable way to use the exfiltrators with them, since the handler either needs to +/// terminate the process or somehow recover from the situation. Things based on exfiltrators do +/// neither, which would cause an UB and therefore these values just don't make sense. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[non_exhaustive] +pub enum Cause { + /// The cause is unknown. + /// + /// Some systems don't fill this in. Some systems have values we don't understand. Some signals + /// don't have specific reasons to come to being. + Unknown, + + /// Sent by the kernel. + /// + /// This probably exists only on Linux. + Kernel, + + /// The signal was sent by other process. + Sent(Sent), + + /// A `SIGCHLD`, caused by a child process changing state. + Chld(Chld), +} + +impl From<ICause> for Cause { + fn from(c: ICause) -> Cause { + match c { + ICause::Kernel => Cause::Kernel, + ICause::User => Cause::Sent(Sent::User), + ICause::TKill => Cause::Sent(Sent::TKill), + ICause::Queue => Cause::Sent(Sent::Queue), + ICause::MesgQ => Cause::Sent(Sent::MesgQ), + ICause::Exited => Cause::Chld(Chld::Exited), + ICause::Killed => Cause::Chld(Chld::Killed), + ICause::Dumped => Cause::Chld(Chld::Dumped), + ICause::Trapped => Cause::Chld(Chld::Trapped), + ICause::Stopped => Cause::Chld(Chld::Stopped), + ICause::Continued => Cause::Chld(Chld::Continued), + // Unknown and possibly others if the underlying lib is updated + _ => Cause::Unknown, + } + } +} + +/// Information about a signal and its origin. +/// +/// This is produced by the [`WithOrigin`] exfiltrator (or can be [extracted][Origin::extract] from +/// `siginfo_t` by hand). +#[derive(Clone, Eq, PartialEq)] +#[non_exhaustive] +pub struct Origin { + /// The signal that happened. + pub signal: c_int, + + /// Information about the process that caused the signal. + /// + /// Note that not all signals are caused by a specific process or have the information + /// available („fault“ signals like `SIGBUS` don't have, any signal may be sent by the kernel + /// instead of a specific process). + /// + /// This is filled in whenever available. For most signals, this is the process that sent the + /// signal (by `kill` or similar), for `SIGCHLD` it is the child that caused the signal. + pub process: Option<Process>, + + /// How the signal happened. + /// + /// This is a best-effort value. In particular, some systems may have causes not known to this + /// library. Some other systems (MacOS) does not fill the value in so there's no way to know. + /// In all these cases, this will contain [`Cause::Unknown`]. + /// + /// Some values are platform specific and not available on other systems. + /// + /// Future versions may enrich the enum by further values. + pub cause: Cause, +} + +impl Debug for Origin { + fn fmt(&self, fmt: &mut Formatter) -> FmtResult { + fn named_signal(sig: c_int) -> String { + low_level::signal_name(sig) + .map(|n| format!("{} ({})", n, sig)) + .unwrap_or_else(|| sig.to_string()) + } + fmt.debug_struct("Origin") + .field("signal", &named_signal(self.signal)) + .field("process", &self.process) + .field("cause", &self.cause) + .finish() + } +} + +impl Origin { + /// Extracts the Origin from a raw `siginfo_t` structure. + /// + /// This function is async-signal-safe, can be called inside a signal handler. + /// + /// # Safety + /// + /// On systems where the structure is backed by an union on the C side, this requires the + /// `si_code` and `si_signo` fields must be set properly according to what fields are + /// available. + /// + /// The value passed by kernel satisfies this, care must be taken only when constructed + /// manually. + pub unsafe fn extract(info: &siginfo_t) -> Self { + let cause = sighook_signal_cause(info); + let process = if cause.has_process() { + let process = Process::extract(info); + // On macos we don't have the si_code to go by, but we can go by the values being + // empty there. + if cfg!(target_os = "macos") && process.pid == 0 && process.uid == 0 { + None + } else { + Some(process) + } + } else { + None + }; + let signal = info.si_signo; + Origin { + cause: cause.into(), + signal, + process, + } + } +} diff --git a/vendor/signal-hook/src/low_level/signal_details.rs b/vendor/signal-hook/src/low_level/signal_details.rs new file mode 100644 index 000000000..303f4e422 --- /dev/null +++ b/vendor/signal-hook/src/low_level/signal_details.rs @@ -0,0 +1,255 @@ +//! Providing auxiliary information for signals. + +use std::io::Error; +use std::mem; +use std::ptr; + +use libc::{c_int, EINVAL}; +#[cfg(not(windows))] +use libc::{sigset_t, SIG_UNBLOCK}; + +use crate::consts::signal::*; +use crate::low_level; + +#[derive(Clone, Copy, Debug)] +enum DefaultKind { + Ignore, + #[cfg(not(windows))] + Stop, + Term, +} + +struct Details { + signal: c_int, + name: &'static str, + default_kind: DefaultKind, +} + +macro_rules! s { + ($name: expr, $kind: ident) => { + Details { + signal: $name, + name: stringify!($name), + default_kind: DefaultKind::$kind, + } + }; +} + +#[cfg(not(windows))] +const DETAILS: &[Details] = &[ + s!(SIGABRT, Term), + s!(SIGALRM, Term), + s!(SIGBUS, Term), + s!(SIGCHLD, Ignore), + // Technically, continue the process... but this is not done *by* the process. + s!(SIGCONT, Ignore), + s!(SIGFPE, Term), + s!(SIGHUP, Term), + s!(SIGILL, Term), + s!(SIGINT, Term), + #[cfg(any( + target_os = "freebsd", + target_os = "dragonfly", + target_os = "netbsd", + target_os = "openbsd", + target_os = "macos" + ))] + s!(SIGINFO, Ignore), + #[cfg(not(target_os = "haiku"))] + s!(SIGIO, Ignore), + // Can't override anyway, but... + s!(SIGKILL, Term), + s!(SIGPIPE, Term), + s!(SIGPROF, Term), + s!(SIGQUIT, Term), + s!(SIGSEGV, Term), + // Can't override anyway, but... + s!(SIGSTOP, Stop), + s!(SIGSYS, Term), + s!(SIGTERM, Term), + s!(SIGTRAP, Term), + s!(SIGTSTP, Stop), + s!(SIGTTIN, Stop), + s!(SIGTTOU, Stop), + s!(SIGURG, Ignore), + s!(SIGUSR1, Term), + s!(SIGUSR2, Term), + s!(SIGVTALRM, Term), + s!(SIGWINCH, Ignore), + s!(SIGXCPU, Term), + s!(SIGXFSZ, Term), +]; + +#[cfg(windows)] +const DETAILS: &[Details] = &[ + s!(SIGABRT, Term), + s!(SIGFPE, Term), + s!(SIGILL, Term), + s!(SIGINT, Term), + s!(SIGSEGV, Term), + s!(SIGTERM, Term), +]; + +/// Provides a human-readable name of a signal. +/// +/// Note that the name does not have to be known (in case it is some less common, or non-standard +/// signal). +/// +/// # Examples +/// +/// ``` +/// # use signal_hook::low_level::signal_name; +/// assert_eq!("SIGKILL", signal_name(9).unwrap()); +/// assert!(signal_name(142).is_none()); +/// ``` +pub fn signal_name(signal: c_int) -> Option<&'static str> { + DETAILS.iter().find(|d| d.signal == signal).map(|d| d.name) +} + +#[cfg(not(windows))] +fn restore_default(signal: c_int) -> Result<(), Error> { + unsafe { + // A C structure, supposed to be memset to 0 before use. + let mut action: libc::sigaction = mem::zeroed(); + #[cfg(target_os = "aix")] + { + action.sa_union.__su_sigaction = mem::transmute::< + usize, + extern "C" fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void), + >(libc::SIG_DFL); + } + #[cfg(not(target_os = "aix"))] + { action.sa_sigaction = libc::SIG_DFL as _; } + if libc::sigaction(signal, &action, ptr::null_mut()) == 0 { + Ok(()) + } else { + Err(Error::last_os_error()) + } + } +} + +#[cfg(windows)] +fn restore_default(signal: c_int) -> Result<(), Error> { + unsafe { + // SIG_DFL = 0, but not in libc :-( + if libc::signal(signal, 0) == 0 { + Ok(()) + } else { + Err(Error::last_os_error()) + } + } +} + +/// Emulates the behaviour of a default handler for the provided signal. +/// +/// This function does its best to provide the same action as the default handler would do, without +/// disrupting the rest of the handling of such signal in the application. It is also +/// async-signal-safe. +/// +/// This function necessarily looks up the appropriate action in a table. That means it is possible +/// your system has a signal that is not known to this function. In such case an error is returned +/// (equivalent of `EINVAL`). +/// +/// See also the [`register_conditional_default`][crate::flag::register_conditional_default]. +/// +/// # Warning +/// +/// There's a short race condition in case of signals that terminate (either with or without a core +/// dump). The emulation first resets the signal handler back to default (as the application is +/// going to end, it's not a problem) and invokes it. But if some other thread installs a signal +/// handler in the meantime (without assistance from `signal-hook`), it can happen this will be +/// invoked by the re-raised signal. +/// +/// This function will still terminate the application (there's a fallback on `abort`), the risk is +/// invoking the newly installed signal handler. Note that manipulating the low-level signals is +/// always racy in a multi-threaded program, therefore the described situation is already +/// discouraged. +/// +/// If you are uneasy about such race condition, the recommendation is to run relevant termination +/// routine manually ([`exit`][super::exit] or [`abort`][super::abort]); they always do what they +/// say, but slightly differ in externally observable behaviour from termination by a signal (the +/// exit code will specify that the application exited, not that it terminated with a signal in the +/// first case, and `abort` terminates on `SIGABRT`, so the detected termination signal may be +/// different). +pub fn emulate_default_handler(signal: c_int) -> Result<(), Error> { + #[cfg(not(windows))] + { + if signal == SIGSTOP || signal == SIGKILL { + return low_level::raise(signal); + } + } + let kind = DETAILS + .iter() + .find(|d| d.signal == signal) + .map(|d| d.default_kind) + .ok_or_else(|| Error::from_raw_os_error(EINVAL))?; + match kind { + DefaultKind::Ignore => Ok(()), + #[cfg(not(windows))] + DefaultKind::Stop => low_level::raise(SIGSTOP), + DefaultKind::Term => { + if let Ok(()) = restore_default(signal) { + #[cfg(not(windows))] + unsafe { + #[allow(deprecated)] + let mut newsigs: sigset_t = mem::zeroed(); + + // Some android versions don't have the sigemptyset and sigaddset. + // Unfortunately, we don't have an access to the android _version_. We just + // know that 64bit versions are all OK, so this is a best-effort guess. + // + // For the affected/guessed versions, we provide our own implementation. We + // hope it to be correct (it's inspired by a libc implementation and we assume + // the kernel uses the same format ‒ it's unlikely to be different both because + // of compatibility and because there's really nothing to invent about a + // bitarray). + // + // We use the proper way for other systems. + #[cfg(all(target_os = "android", target_pointer_width = "32"))] + unsafe fn prepare_sigset(set: *mut sigset_t, mut signal: c_int) { + signal -= 1; + let set_raw: *mut libc::c_ulong = set.cast(); + let size = mem::size_of::<libc::c_ulong>(); + assert_eq!(set_raw as usize % mem::align_of::<libc::c_ulong>(), 0); + let pos = signal as usize / size; + assert!(pos < mem::size_of::<sigset_t>() / size); + let bit = 1 << (signal as usize % size); + set_raw.add(pos).write(bit); + } + + #[cfg(not(all(target_os = "android", target_pointer_width = "32")))] + unsafe fn prepare_sigset(set: *mut sigset_t, signal: c_int) { + libc::sigemptyset(set); + libc::sigaddset(set, signal); + } + + prepare_sigset(&mut newsigs, signal); + // Ignore the result, if it doesn't work, we try anyway + // Also, sigprocmask is unspecified, but available on more systems. And we want + // to just enable _something_. And if it doesn't work, we'll terminate + // anyway... It's not UB, so we are good. + libc::sigprocmask(SIG_UNBLOCK, &newsigs, ptr::null_mut()); + } + let _ = low_level::raise(signal); + } + // Fallback if anything failed or someone managed to put some other action in in + // between. + unsafe { libc::abort() } + } + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn existing() { + assert_eq!("SIGTERM", signal_name(SIGTERM).unwrap()); + } + + #[test] + fn unknown() { + assert!(signal_name(128).is_none()); + } +} diff --git a/vendor/signal-hook/tests/default.rs b/vendor/signal-hook/tests/default.rs new file mode 100644 index 000000000..bccf55891 --- /dev/null +++ b/vendor/signal-hook/tests/default.rs @@ -0,0 +1,25 @@ +//! 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); +} diff --git a/vendor/signal-hook/tests/iterator.rs b/vendor/signal-hook/tests/iterator.rs new file mode 100644 index 000000000..90e0598fe --- /dev/null +++ b/vendor/signal-hook/tests/iterator.rs @@ -0,0 +1,260 @@ +#![cfg(not(windows))] + +extern crate signal_hook; + +use std::collections::HashSet; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::mpsc::{self, RecvTimeoutError}; +use std::sync::Arc; +use std::thread::{self, JoinHandle}; +use std::time::Duration; + +use signal_hook::consts::{SIGUSR1, SIGUSR2}; +use signal_hook::iterator::{Handle, Signals}; +use signal_hook::low_level::raise; + +use serial_test::serial; + +fn send_sigusr1() { + raise(SIGUSR1).unwrap(); +} + +fn send_sigusr2() { + raise(SIGUSR2).unwrap(); +} + +fn setup_without_any_signals() -> (Signals, Handle) { + let signals = Signals::new(&[]).unwrap(); + let controller = signals.handle(); + (signals, controller) +} + +fn setup_for_sigusr2() -> (Signals, Handle) { + let signals = Signals::new(&[SIGUSR2]).unwrap(); + let controller = signals.handle(); + (signals, controller) +} + +macro_rules! assert_signals { + ($actual:expr, $($expected:expr),+ $(,)?) => { + let actual = $actual.collect::<HashSet<libc::c_int>>(); + let expected = vec!($($expected),+).into_iter().collect::<HashSet<libc::c_int>>(); + assert_eq!(actual, expected); + }; +} + +macro_rules! assert_no_signals { + ($signals:expr) => { + assert_eq!($signals.next(), None); + }; +} + +#[test] +#[serial] +fn forever_terminates_when_closed() { + let (mut signals, controller) = setup_for_sigusr2(); + + // Detect early terminations. + let stopped = Arc::new(AtomicBool::new(false)); + + let stopped_bg = Arc::clone(&stopped); + let thread = 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 &mut signals {} + + stopped_bg.store(true, Ordering::SeqCst); + }); + + // Wait a bit to see if the thread terminates by itself. + thread::sleep(Duration::from_millis(100)); + assert!(!stopped.load(Ordering::SeqCst)); + + controller.close(); + + 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] +#[serial] +fn signals_block_wait() { + let mut signals = Signals::new(&[SIGUSR2]).unwrap(); + let (s, r) = mpsc::channel(); + let finish = Arc::new(AtomicBool::new(false)); + let thread_id = thread::spawn({ + let finish = Arc::clone(&finish); + 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() { + if finish.load(Ordering::SeqCst) { + // Asked to terminate at the end of the thread. Do so (but without + // signalling the receipt). + return; + } else { + panic!("Someone really did send us SIGUSR2, which breaks the test"); + } + } + } + let _ = s.send(()); + } + }); + + // A RAII guard to make sure we shut down the thread even if the test fails. + struct ThreadGuard { + thread: Option<JoinHandle<()>>, + finish: Arc<AtomicBool>, + } + + impl ThreadGuard { + fn shutdown(&mut self) { + // Tell it to shut down + self.finish.store(true, Ordering::SeqCst); + // Wake it up + send_sigusr2(); + // Wait for it to actually terminate. + if let Some(thread) = self.thread.take() { + thread.join().unwrap(); // Propagate panics + } + } + } + + impl Drop for ThreadGuard { + fn drop(&mut self) { + self.shutdown(); // OK if done twice, won't have the thread any more. + } + } + + let mut bg_thread = ThreadGuard { + thread: Some(thread_id), + finish, + }; + + let err = r + .recv_timeout(Duration::from_millis(100)) + .expect_err("Wait didn't wait properly"); + assert_eq!(err, RecvTimeoutError::Timeout); + + bg_thread.shutdown(); +} + +#[test] +#[serial] +fn pending_doesnt_block() { + let (mut signals, _) = setup_for_sigusr2(); + + let mut recieved_signals = signals.pending(); + + assert_no_signals!(recieved_signals); +} + +#[test] +#[serial] +fn wait_returns_recieved_signals() { + let (mut signals, _) = setup_for_sigusr2(); + send_sigusr2(); + + let recieved_signals = signals.wait(); + + assert_signals!(recieved_signals, SIGUSR2); +} + +#[test] +#[serial] +fn forever_returns_recieved_signals() { + let (mut signals, _) = setup_for_sigusr2(); + send_sigusr2(); + + let signal = signals.forever().take(1); + + assert_signals!(signal, SIGUSR2); +} + +#[test] +#[serial] +fn wait_doesnt_block_when_closed() { + let (mut signals, controller) = setup_for_sigusr2(); + controller.close(); + + let mut recieved_signals = signals.wait(); + + assert_no_signals!(recieved_signals); +} + +#[test] +#[serial] +fn wait_unblocks_when_closed() { + let (mut signals, controller) = setup_without_any_signals(); + + let thread = thread::spawn(move || { + signals.wait(); + }); + + controller.close(); + + thread.join().unwrap(); +} + +#[test] +#[serial] +fn forever_doesnt_block_when_closed() { + let (mut signals, controller) = setup_for_sigusr2(); + controller.close(); + + let mut signal = signals.forever(); + + assert_no_signals!(signal); +} + +#[test] +#[serial] +fn add_signal_after_creation() { + let (mut signals, _) = setup_without_any_signals(); + signals.add_signal(SIGUSR1).unwrap(); + + send_sigusr1(); + + assert_signals!(signals.pending(), SIGUSR1); +} + +#[test] +#[serial] +fn delayed_signal_consumed() { + let (mut signals, _) = setup_for_sigusr2(); + signals.add_signal(SIGUSR1).unwrap(); + + send_sigusr1(); + let mut recieved_signals = signals.wait(); + send_sigusr2(); + + assert_signals!(recieved_signals, SIGUSR1, SIGUSR2); + + // The pipe still contains the byte from the second + // signal and so wait won't block but won't return + // a signal. + recieved_signals = signals.wait(); + assert_no_signals!(recieved_signals); +} + +#[test] +#[serial] +fn is_closed_initially_returns_false() { + let (_, controller) = setup_for_sigusr2(); + + assert!(!controller.is_closed()); +} + +#[test] +#[serial] +fn is_closed_returns_true_when_closed() { + let (_, controller) = setup_for_sigusr2(); + controller.close(); + + assert!(controller.is_closed()); +} diff --git a/vendor/signal-hook/tests/shutdown.rs b/vendor/signal-hook/tests/shutdown.rs new file mode 100644 index 000000000..381fab729 --- /dev/null +++ b/vendor/signal-hook/tests/shutdown.rs @@ -0,0 +1,81 @@ +//! Tests for the shutdown. +//! +//! 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. + +use std::io::Error; +use std::ptr; +use std::sync::atomic::AtomicBool; +use std::sync::Arc; +use std::thread; +use std::time::Duration; + +use signal_hook::consts::signal::*; +use signal_hook::flag; +use signal_hook::low_level; + +fn do_test<C: FnOnce()>(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() { + // Make sure we have some signal handler, not the default. + unsafe { low_level::register(SIGTERM, || ()).unwrap() }; + let shutdown_cond = Arc::new(AtomicBool::new(false)); + // „disarmed“ shutdown + flag::register_conditional_shutdown(SIGTERM, 0, Arc::clone(&shutdown_cond)).unwrap(); + // But arm at the first SIGTERM + flag::register(SIGTERM, shutdown_cond).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 mut signals = signal_hook::iterator::Signals::new(&[libc::SIGTERM]).unwrap(); + assert_eq!(Some(SIGTERM), signals.into_iter().next()); + flag::register_conditional_shutdown(SIGTERM, 0, Arc::new(AtomicBool::new(true))).unwrap(); + } + do_test(hook); +} |