Vendor dependencies
Let's see how I like this workflow.
This commit is contained in:
parent
34d1830413
commit
9c435dc440
7500 changed files with 1665121 additions and 99 deletions
1
vendor/signal-hook/.cargo-checksum.json
vendored
Normal file
1
vendor/signal-hook/.cargo-checksum.json
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"files":{"CHANGELOG.md":"bbff0d30c90dda500266d23e59c1e173d663d09e235f9d70140a9bebbd9ed48a","Cargo.lock":"419e8ab688749f60dc387693e1343e8b9f454b078b05f96c9105fa779e01627a","Cargo.toml":"91bbb061ef8f65702a171a503869fad83c7ff4a93b6c7852b02af16527f451ec","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":"068e010f38136fd38b88bba360acfc27c09cbc81130bd9a04accc52ca161353e","src/iterator/exfiltrator/mod.rs":"c5476b32f00094e7556350c79bff7cec88e890750a42b613a5bf00e33234311f","src/iterator/exfiltrator/origin.rs":"ada8f6289c9b31d523f3cc9e02d533a3f348cfad6f5fc59ab929f851816ed156","src/iterator/exfiltrator/raw.rs":"cbb0709ec2ba778d7a42512d82845e93f21088ed3a0f5d3415ccc34747e00f62","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":"d9866259b3de0dacd5d7a2e12215c5ef14d6772e19be06b40b7f1d7ae87024c3","src/low_level/siginfo.rs":"3a416031a654add7b39a2a6c0328e6c60dbf33ca972a45ef11eaf198615a0aaf","src/low_level/signal_details.rs":"c2242f7457f7a6c1ef44df691f7ee3005f18fc56ce5b11894f5d7dab70578763","tests/default.rs":"2e6e400990d31a5968f6909278e9cf20b75ba7f1a92b8485122ac790a2e94a44","tests/iterator.rs":"1533f9722c047a221a6e8903d179cace76c395fff54df010e42fbcaabeca7bc9","tests/shutdown.rs":"3ca8dbf94eead616bd47968f029a91c6bdffc9fb44be3f004d6e8fe2ac46db00"},"package":"a253b5e89e2698464fc26b545c9edceb338e18a89effeeecfea192c3025be29d"}
|
||||
251
vendor/signal-hook/CHANGELOG.md
vendored
Normal file
251
vendor/signal-hook/CHANGELOG.md
vendored
Normal file
|
|
@ -0,0 +1,251 @@
|
|||
# 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.
|
||||
195
vendor/signal-hook/Cargo.lock
generated
vendored
Normal file
195
vendor/signal-hook/Cargo.lock
generated
vendored
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[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.72"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[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.109"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f98a04dce437184842841303488f70d0188c5f51437d2a834dc097eafa909a01"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109"
|
||||
dependencies = [
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
|
||||
dependencies = [
|
||||
"instant",
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"instant",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"smallvec",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb37d2df5df740e582f28f8560cf425f52bb267d872fe58358eadb554909f07a"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[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.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0bccbcf40c8938196944a3da0e133e031a33f4d6b72db3bda3cc556e361905d"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"parking_lot",
|
||||
"serial_test_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serial_test_derive"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2acd6defeddb41eb60bb468f8825d0cfd0c2a76bc03bfd235b6a1dc4f6a1ad5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook"
|
||||
version = "0.3.14"
|
||||
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.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.82"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
66
vendor/signal-hook/Cargo.toml
vendored
Normal file
66
vendor/signal-hook/Cargo.toml
vendored
Normal file
|
|
@ -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.14"
|
||||
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.5"
|
||||
|
||||
[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"
|
||||
201
vendor/signal-hook/LICENSE-APACHE
vendored
Normal file
201
vendor/signal-hook/LICENSE-APACHE
vendored
Normal file
|
|
@ -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.
|
||||
25
vendor/signal-hook/LICENSE-MIT
vendored
Normal file
25
vendor/signal-hook/LICENSE-MIT
vendored
Normal file
|
|
@ -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.
|
||||
70
vendor/signal-hook/README.md
vendored
Normal file
70
vendor/signal-hook/README.md
vendored
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
# Signal-hook
|
||||
|
||||
[](https://github.com/vorner/signal-hook/actions)
|
||||
[](https://codecov.io/gh/vorner/signal-hook)
|
||||
[](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.
|
||||
9
vendor/signal-hook/build.rs
vendored
Normal file
9
vendor/signal-hook/build.rs
vendored
Normal file
|
|
@ -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() {}
|
||||
31
vendor/signal-hook/ci-check.sh
vendored
Normal file
31
vendor/signal-hook/ci-check.sh
vendored
Normal file
|
|
@ -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
|
||||
27
vendor/signal-hook/examples/print.rs
vendored
Normal file
27
vendor/signal-hook/examples/print.rs
vendored
Normal file
|
|
@ -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(())
|
||||
}
|
||||
0
vendor/signal-hook/rustfmt.toml
vendored
Normal file
0
vendor/signal-hook/rustfmt.toml
vendored
Normal file
283
vendor/signal-hook/src/flag.rs
vendored
Normal file
283
vendor/signal-hook/src/flag.rs
vendored
Normal file
|
|
@ -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
|
||||
}
|
||||
490
vendor/signal-hook/src/iterator/backend.rs
vendored
Normal file
490
vendor/signal-hook/src/iterator/backend.rs
vendored
Normal file
|
|
@ -0,0 +1,490 @@
|
|||
//! 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.
|
||||
while libc::recv(
|
||||
self.read.as_raw_fd(),
|
||||
buff.as_mut_ptr() as *mut libc::c_void,
|
||||
SIZE,
|
||||
libc::MSG_DONTWAIT,
|
||||
) > 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>;
|
||||
152
vendor/signal-hook/src/iterator/exfiltrator/mod.rs
vendored
Normal file
152
vendor/signal-hook/src/iterator/exfiltrator/mod.rs
vendored
Normal file
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
66
vendor/signal-hook/src/iterator/exfiltrator/origin.rs
vendored
Normal file
66
vendor/signal-hook/src/iterator/exfiltrator/origin.rs
vendored
Normal file
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
95
vendor/signal-hook/src/iterator/exfiltrator/raw.rs
vendored
Normal file
95
vendor/signal-hook/src/iterator/exfiltrator/raw.rs
vendored
Normal file
|
|
@ -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::new(Channel::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");
|
||||
}
|
||||
}
|
||||
323
vendor/signal-hook/src/iterator/mod.rs
vendored
Normal file
323
vendor/signal-hook/src/iterator/mod.rs
vendored
Normal file
|
|
@ -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>;
|
||||
414
vendor/signal-hook/src/lib.rs
vendored
Normal file
414
vendor/signal-hook/src/lib.rs
vendored
Normal file
|
|
@ -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;
|
||||
235
vendor/signal-hook/src/low_level/channel.rs
vendored
Normal file
235
vendor/signal-hook/src/low_level/channel.rs
vendored
Normal file
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
55
vendor/signal-hook/src/low_level/extract.c
vendored
Normal file
55
vendor/signal-hook/src/low_level/extract.c
vendored
Normal file
|
|
@ -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;
|
||||
}
|
||||
59
vendor/signal-hook/src/low_level/mod.rs
vendored
Normal file
59
vendor/signal-hook/src/low_level/mod.rs
vendored
Normal file
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
260
vendor/signal-hook/src/low_level/pipe.rs
vendored
Normal file
260
vendor/signal-hook/src/low_level/pipe.rs
vendored
Normal file
|
|
@ -0,0 +1,260 @@
|
|||
//! 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;
|
||||
|
||||
#[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, libc::MSG_DONTWAIT),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// 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, libc::MSG_DONTWAIT) };
|
||||
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(())
|
||||
}
|
||||
}
|
||||
261
vendor/signal-hook/src/low_level/siginfo.rs
vendored
Normal file
261
vendor/signal-hook/src/low_level/siginfo.rs
vendored
Normal file
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
247
vendor/signal-hook/src/low_level/signal_details.rs
vendored
Normal file
247
vendor/signal-hook/src/low_level/signal_details.rs
vendored
Normal file
|
|
@ -0,0 +1,247 @@
|
|||
//! 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();
|
||||
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());
|
||||
}
|
||||
}
|
||||
25
vendor/signal-hook/tests/default.rs
vendored
Normal file
25
vendor/signal-hook/tests/default.rs
vendored
Normal file
|
|
@ -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);
|
||||
}
|
||||
260
vendor/signal-hook/tests/iterator.rs
vendored
Normal file
260
vendor/signal-hook/tests/iterator.rs
vendored
Normal file
|
|
@ -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());
|
||||
}
|
||||
81
vendor/signal-hook/tests/shutdown.rs
vendored
Normal file
81
vendor/signal-hook/tests/shutdown.rs
vendored
Normal file
|
|
@ -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);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue