mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-07 18:04:46 +00:00
Bug 1837084 - Don't enable all tokio features in http3server r=necko-reviewers,supply-chain-reviewers,kershaw
It doesn't need them all. Differential Revision: https://phabricator.services.mozilla.com/D180155
This commit is contained in:
parent
26ecfb32d7
commit
889fd52ec7
12
Cargo.lock
generated
12
Cargo.lock
generated
@ -4761,15 +4761,6 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3"
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "siphasher"
|
||||
version = "0.3.10"
|
||||
@ -5273,10 +5264,7 @@ dependencies = [
|
||||
"memchr",
|
||||
"mio 0.8.0",
|
||||
"num_cpus",
|
||||
"once_cell",
|
||||
"parking_lot 0.12.999",
|
||||
"pin-project-lite",
|
||||
"signal-hook-registry",
|
||||
"socket2",
|
||||
"tokio-macros",
|
||||
"winapi",
|
||||
|
@ -17,7 +17,7 @@ base64 = "0.21"
|
||||
cfg-if = "1.0"
|
||||
http = "0.2.8"
|
||||
hyper = { version = "0.14", features = ["full"] }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
tokio = { version = "1", features = ["rt-multi-thread"] }
|
||||
|
||||
[dependencies.neqo-crypto]
|
||||
tag = "v0.6.4"
|
||||
|
@ -789,10 +789,6 @@ criteria = "safe-to-deploy"
|
||||
version = "1.1.0"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.signal-hook-registry]]
|
||||
version = "1.4.1"
|
||||
criteria = "safe-to-run"
|
||||
|
||||
[[exemptions.siphasher]]
|
||||
version = "0.3.10"
|
||||
criteria = "safe-to-deploy"
|
||||
|
2
third_party/rust/cose/.cargo-checksum.json
vendored
2
third_party/rust/cose/.cargo-checksum.json
vendored
@ -1 +1 @@
|
||||
{"files":{"Cargo.toml":"e4af309a907a63866cc85b7e8d878d083790ef9b5733a5129906eb26eedfd80c","LICENSE":"1f256ecad192880510e84ad60474eab7589218784b9a50bc7ceee34c2b91f1d5","README.md":"981c13c037304ca06c34d8518f2d2e0021867dfd36cb711efb8f6c5e2fdb0123","build.rs":"a2b798bbeaf8ef19a9bd8c1e24b3fd3899a5b4b3e121e5e09794e4e2b35971dd","examples/sign_verify/main.rs":"fbe4b9c73b23e1ef364126f453f749fefb67ab45703bf809a5eed910a25e461e","examples/sign_verify/nss.rs":"a1d133142efc0ac6564f0b9587890587f1ecaa7404ac0c4c8907de6d43de3267","examples/sign_verify/test_nss.rs":"be41ebe0a82b6172297b10c13767e4768f0b613ac331b554f6e8c2c7a20c0bc8","examples/sign_verify/test_setup.rs":"d323c3818525a43b71c3a121b39043c5debdff303fa3cfec230853c96ff477eb","examples/sign_verify/util_test.rs":"48d52f3ca3e93b670a1d69f8443358260c1ae61d7977a59d922696811320d4c3","rustfmt.toml":"e97717e906fcd3eeb86dcee52ed26f13e1884597b016a27172229d9c78dd3d57","src/cose.rs":"104e06843f4cdffe2ca6f42f46c51c79d685c18d2ad92b65811e3ceffbd90e07","src/decoder.rs":"d84fc785715823963551466175af0bb86a16cee58ae95b54bfd613d390bc4d82","src/test_cose.rs":"849ec936a00eb438a08eb85380b3e4ba8d8c5a5cf674b272e0fd8e671ab6d5ca","src/test_setup.rs":"e26f290831343cbb4e2b2ec7d1be34c7b900eb8c87abd6f40629372a87b6e992","src/util.rs":"8cdcdc8a120e71a772af61fa63ffa2d2d2eb572d8a53da3b5f1ce9da784f2662","tools/certs/certs.md":"7a1acd946f5bb5b9b21ebd7653ef9d5746a1ea237131a69218a91dc26eda545a","tools/certs/certs.sh":"a06e1a7bf99316c7800e388d20c1630da7449937635600d9f21d8d93907011bf","tools/certs/ee-p256.certspec":"5a7246c0abf1ee08edb858ce2fd38010de7785a0e8652f2d9a0b7eee7aa39213","tools/certs/ee-p256.keyspec":"eabd2839f9e57cf2c372e686e5856cf651d7f07d0d396b3699d1d228b5931945","tools/certs/ee-p384.certspec":"d2e4fdd6d8f02f22bffa800ac2b7f899f5d826528e7b7d3248e1abea15cd33bd","tools/certs/ee-p521.certspec":"7ad1fc3cdf024dfa7213f3a2875af0ccfa2bd73fddcfaf73223aa25b24ee2cad","tools/certs/ee-rsa.certspec":"dd69ecbb1cdf322fb8ef6eb50c2f033b62e7983b5448b96f1965eee8f85b7bde","tools/certs/int-p256.certspec":"b42a2286339455626b9a8b6c0811b031bf269440c6fcef7478796d02c5491364","tools/certs/int-rsa.certspec":"a0942438c72a3ce83b54c04e4a5d4bff08036c2c9feb7d75a7105bfa4fdc5499","tools/certs/root-p256.certspec":"99c1bb07505ddfc3ada5737d8a1bf4cff7b1a70a79abda9fd45fc3a6e72061fc","tools/certs/root-rsa.certspec":"67903313b6058aa98be0d98564577b0c878c868b6f2a8758f27bb7af17616d8e"},"package":null}
|
||||
{"files":{".travis.yml":"423ecb6dd6dbc8b00fb3d2789ddc89ab4d9c1040ea3d5e467f437728164cd5b9","Cargo.toml":"e4af309a907a63866cc85b7e8d878d083790ef9b5733a5129906eb26eedfd80c","LICENSE":"1f256ecad192880510e84ad60474eab7589218784b9a50bc7ceee34c2b91f1d5","README.md":"981c13c037304ca06c34d8518f2d2e0021867dfd36cb711efb8f6c5e2fdb0123","build.rs":"a2b798bbeaf8ef19a9bd8c1e24b3fd3899a5b4b3e121e5e09794e4e2b35971dd","examples/sign_verify/main.rs":"fbe4b9c73b23e1ef364126f453f749fefb67ab45703bf809a5eed910a25e461e","examples/sign_verify/nss.rs":"a1d133142efc0ac6564f0b9587890587f1ecaa7404ac0c4c8907de6d43de3267","examples/sign_verify/test_nss.rs":"be41ebe0a82b6172297b10c13767e4768f0b613ac331b554f6e8c2c7a20c0bc8","examples/sign_verify/test_setup.rs":"d323c3818525a43b71c3a121b39043c5debdff303fa3cfec230853c96ff477eb","examples/sign_verify/util_test.rs":"48d52f3ca3e93b670a1d69f8443358260c1ae61d7977a59d922696811320d4c3","rustfmt.toml":"e97717e906fcd3eeb86dcee52ed26f13e1884597b016a27172229d9c78dd3d57","src/cose.rs":"104e06843f4cdffe2ca6f42f46c51c79d685c18d2ad92b65811e3ceffbd90e07","src/decoder.rs":"d84fc785715823963551466175af0bb86a16cee58ae95b54bfd613d390bc4d82","src/test_cose.rs":"849ec936a00eb438a08eb85380b3e4ba8d8c5a5cf674b272e0fd8e671ab6d5ca","src/test_setup.rs":"e26f290831343cbb4e2b2ec7d1be34c7b900eb8c87abd6f40629372a87b6e992","src/util.rs":"8cdcdc8a120e71a772af61fa63ffa2d2d2eb572d8a53da3b5f1ce9da784f2662","tools/certs/certs.md":"7a1acd946f5bb5b9b21ebd7653ef9d5746a1ea237131a69218a91dc26eda545a","tools/certs/certs.sh":"a06e1a7bf99316c7800e388d20c1630da7449937635600d9f21d8d93907011bf","tools/certs/ee-p256.certspec":"5a7246c0abf1ee08edb858ce2fd38010de7785a0e8652f2d9a0b7eee7aa39213","tools/certs/ee-p256.keyspec":"eabd2839f9e57cf2c372e686e5856cf651d7f07d0d396b3699d1d228b5931945","tools/certs/ee-p384.certspec":"d2e4fdd6d8f02f22bffa800ac2b7f899f5d826528e7b7d3248e1abea15cd33bd","tools/certs/ee-p521.certspec":"7ad1fc3cdf024dfa7213f3a2875af0ccfa2bd73fddcfaf73223aa25b24ee2cad","tools/certs/ee-rsa.certspec":"dd69ecbb1cdf322fb8ef6eb50c2f033b62e7983b5448b96f1965eee8f85b7bde","tools/certs/int-p256.certspec":"b42a2286339455626b9a8b6c0811b031bf269440c6fcef7478796d02c5491364","tools/certs/int-rsa.certspec":"a0942438c72a3ce83b54c04e4a5d4bff08036c2c9feb7d75a7105bfa4fdc5499","tools/certs/root-p256.certspec":"99c1bb07505ddfc3ada5737d8a1bf4cff7b1a70a79abda9fd45fc3a6e72061fc","tools/certs/root-rsa.certspec":"67903313b6058aa98be0d98564577b0c878c868b6f2a8758f27bb7af17616d8e"},"package":null}
|
28
third_party/rust/cose/.travis.yml
vendored
Normal file
28
third_party/rust/cose/.travis.yml
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
dist: bionic
|
||||
language: rust
|
||||
cache: cargo
|
||||
os:
|
||||
- linux
|
||||
rust:
|
||||
- stable
|
||||
- beta
|
||||
- nightly
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- build-essential
|
||||
- libnss3-dev
|
||||
|
||||
#install:
|
||||
# Apparently cargo install returns a nonzero exit status if
|
||||
# caching succeeds, so just make this always "succeed".
|
||||
# - (cargo install rustfmt --force || true)
|
||||
|
||||
script:
|
||||
#- |
|
||||
# cargo fmt -- --write-mode=diff
|
||||
- |
|
||||
cargo build --features "$FEATURES" &&
|
||||
cargo test &&
|
||||
cargo run --example sign_verify
|
@ -1 +0,0 @@
|
||||
{"files":{"Cargo.toml":"42fe4108f3d88108c7d65d951a56842f47644a8a4e2d6932c34b9a9fae098316","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"503558bfefe66ca15e4e3f7955b3cb0ec87fd52f29bf24b336af7bd00e946d5c","README.md":"56d8abee3efdf82aed1791a81feb60d9db987cedfa9c2e2a6b9451ac94bb88f7","src/half_lock.rs":"548fc2e283ef638a9f90e194d112a11c94205c87004d6da2e65eaa98f7a5a670","src/lib.rs":"1ed9cb19bfcde72036f983e2800ffa10c7ef4df0a0500bc697c49374260f1ac8","tests/unregister_signal.rs":"5baeebbde2bd7e63ae9a1f1e476d33f0bfd368c1edcdab3677de6a62b04f5118"},"package":"d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"}
|
40
third_party/rust/signal-hook-registry/Cargo.toml
vendored
40
third_party/rust/signal-hook-registry/Cargo.toml
vendored
@ -1,40 +0,0 @@
|
||||
# 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]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.1"
|
||||
authors = [
|
||||
"Michal 'vorner' Vaner <vorner@vorner.cz>",
|
||||
"Masaki Hara <ackie.h.gmai@gmail.com>",
|
||||
]
|
||||
description = "Backend crate for signal-hook"
|
||||
documentation = "https://docs.rs/signal-hook-registry"
|
||||
readme = "README.md"
|
||||
keywords = [
|
||||
"signal",
|
||||
"unix",
|
||||
"daemon",
|
||||
]
|
||||
license = "Apache-2.0/MIT"
|
||||
repository = "https://github.com/vorner/signal-hook"
|
||||
|
||||
[dependencies.libc]
|
||||
version = "~0.2"
|
||||
|
||||
[dev-dependencies.signal-hook]
|
||||
version = "~0.3"
|
||||
|
||||
[badges.maintenance]
|
||||
status = "actively-developed"
|
||||
|
||||
[badges.travis-ci]
|
||||
repository = "vorner/signal-hook"
|
201
third_party/rust/signal-hook-registry/LICENSE-APACHE
vendored
201
third_party/rust/signal-hook-registry/LICENSE-APACHE
vendored
@ -1,201 +0,0 @@
|
||||
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.
|
@ -1,25 +0,0 @@
|
||||
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.
|
24
third_party/rust/signal-hook-registry/README.md
vendored
24
third_party/rust/signal-hook-registry/README.md
vendored
@ -1,24 +0,0 @@
|
||||
# Signal-hook-registry
|
||||
|
||||
[![Travis Build Status](https://api.travis-ci.org/vorner/signal-hook.svg?branch=master)](https://travis-ci.org/vorner/signal-hook)
|
||||
|
||||
This is the backend crate for the
|
||||
[signal-hook](https://crates.io/crates/signal-hook) crate. The general direct use of
|
||||
this crate is discouraged. See the
|
||||
[documentation](https://docs.rs/signal-hook-registry) for further details.
|
||||
|
||||
## 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.
|
@ -1,232 +0,0 @@
|
||||
//! The half-lock structure
|
||||
//!
|
||||
//! We need a way to protect the structure with configured hooks ‒ a signal may happen in arbitrary
|
||||
//! thread and needs to read them while another thread might be manipulating the structure.
|
||||
//!
|
||||
//! Under ordinary circumstances we would be happy to just use `Mutex<HashMap<c_int, _>>`. However,
|
||||
//! as we use it in the signal handler, we are severely limited in what we can or can't use. So we
|
||||
//! choose to implement kind of spin-look thing with atomics.
|
||||
//!
|
||||
//! In the reader it is always simply locked and then unlocked, making sure it doesn't disappear
|
||||
//! while in use.
|
||||
//!
|
||||
//! The writer has a separate mutex (that prevents other writers; this is used outside of the
|
||||
//! signal handler), makes a copy of the data and swaps an atomic pointer to the data structure.
|
||||
//! But it waits until everything is unlocked (no signal handler has the old data) for dropping the
|
||||
//! old instance. There's a generation trick to make sure that new signal locks another instance.
|
||||
//!
|
||||
//! The downside is, this is an active spin lock at the writer end. However, we assume than:
|
||||
//!
|
||||
//! * Signals are one time setup before we actually have threads. We just need to make *sure* we
|
||||
//! are safe even if this is not true.
|
||||
//! * Signals are rare, happening at the same time as the write even rarer.
|
||||
//! * Signals are short, as there is mostly nothing allowed inside them anyway.
|
||||
//! * Our tool box is severely limited.
|
||||
//!
|
||||
//! Therefore this is hopefully reasonable trade-off.
|
||||
//!
|
||||
//! # Atomic orderings
|
||||
//!
|
||||
//! The whole code uses SeqCst conservatively. Atomics are not used because of performance here and
|
||||
//! are the minor price around signals anyway. But the comments state which orderings should be
|
||||
//! enough in practice in case someone wants to get inspired (but do make your own check through
|
||||
//! them anyway).
|
||||
|
||||
use std::isize;
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::Deref;
|
||||
use std::sync::atomic::{self, AtomicPtr, AtomicUsize, Ordering};
|
||||
use std::sync::{Mutex, MutexGuard, PoisonError};
|
||||
use std::thread;
|
||||
|
||||
use libc;
|
||||
|
||||
const YIELD_EVERY: usize = 16;
|
||||
const MAX_GUARDS: usize = (isize::MAX) as usize;
|
||||
|
||||
pub(crate) struct ReadGuard<'a, T: 'a> {
|
||||
data: &'a T,
|
||||
lock: &'a AtomicUsize,
|
||||
}
|
||||
|
||||
impl<'a, T> Deref for ReadGuard<'a, T> {
|
||||
type Target = T;
|
||||
fn deref(&self) -> &T {
|
||||
self.data
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Drop for ReadGuard<'a, T> {
|
||||
fn drop(&mut self) {
|
||||
// We effectively unlock; Release would be enough.
|
||||
self.lock.fetch_sub(1, Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct WriteGuard<'a, T: 'a> {
|
||||
_guard: MutexGuard<'a, ()>,
|
||||
lock: &'a HalfLock<T>,
|
||||
data: &'a T,
|
||||
}
|
||||
|
||||
impl<'a, T> WriteGuard<'a, T> {
|
||||
pub(crate) fn store(&mut self, val: T) {
|
||||
// Move to the heap and convert to raw pointer for AtomicPtr.
|
||||
let new = Box::into_raw(Box::new(val));
|
||||
|
||||
self.data = unsafe { &*new };
|
||||
|
||||
// We can just put the new value in here safely, we worry only about dropping the old one.
|
||||
// Release might (?) be enough, to "upload" the data.
|
||||
let old = self.lock.data.swap(new, Ordering::SeqCst);
|
||||
|
||||
// Now we make sure there's no reader having the old data.
|
||||
self.lock.write_barrier();
|
||||
|
||||
drop(unsafe { Box::from_raw(old) });
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Deref for WriteGuard<'a, T> {
|
||||
type Target = T;
|
||||
fn deref(&self) -> &T {
|
||||
// Protected by that mutex
|
||||
self.data
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct HalfLock<T> {
|
||||
// We conceptually contain an instance of T
|
||||
_t: PhantomData<T>,
|
||||
// The actual data as a pointer.
|
||||
data: AtomicPtr<T>,
|
||||
// The generation of the data. Influences which slot of the lock counter we use.
|
||||
generation: AtomicUsize,
|
||||
// How many active locks are there?
|
||||
lock: [AtomicUsize; 2],
|
||||
// Mutex for the writers; only one writer.
|
||||
write_mutex: Mutex<()>,
|
||||
}
|
||||
|
||||
impl<T> HalfLock<T> {
|
||||
pub(crate) fn new(data: T) -> Self {
|
||||
// Move to the heap so we can safely point there. Then convert to raw pointer as AtomicPtr
|
||||
// operates on raw pointers. The AtomicPtr effectively acts like Box for us semantically.
|
||||
let ptr = Box::into_raw(Box::new(data));
|
||||
Self {
|
||||
_t: PhantomData,
|
||||
data: AtomicPtr::new(ptr),
|
||||
generation: AtomicUsize::new(0),
|
||||
lock: [AtomicUsize::new(0), AtomicUsize::new(0)],
|
||||
write_mutex: Mutex::new(()),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn read(&self) -> ReadGuard<T> {
|
||||
// Relaxed should be enough; we only pick one or the other slot and the writer observes
|
||||
// that both were 0 at some time. So the actual value doesn't really matter for safety,
|
||||
// only the changing improves the performance.
|
||||
let gen = self.generation.load(Ordering::SeqCst);
|
||||
let lock = &self.lock[gen % 2];
|
||||
// Effectively locking something, acquire should be enough.
|
||||
let guard_cnt = lock.fetch_add(1, Ordering::SeqCst);
|
||||
|
||||
// This is to prevent overflowing the counter in some degenerate cases, which could lead to
|
||||
// UB (freeing data while still in use). However, as this data structure is used only
|
||||
// internally and it's not possible to leak the guard and the guard itself takes some
|
||||
// memory, it should be really impossible to trigger this case. Still, we include it from
|
||||
// abundance of caution.
|
||||
//
|
||||
// This technically is not fully correct as enough threads being in between here and the
|
||||
// abort below could still overflow it and it could get freed for some *other* thread, but
|
||||
// that would mean having too many active threads to fit into RAM too and is even more
|
||||
// absurd corner case than the above.
|
||||
if guard_cnt > MAX_GUARDS {
|
||||
unsafe { libc::abort() };
|
||||
}
|
||||
|
||||
// Acquire should be enough; we need to "download" the data, paired with the swap on the
|
||||
// same pointer.
|
||||
let data = self.data.load(Ordering::SeqCst);
|
||||
// Safe:
|
||||
// * It did point to valid data when put in.
|
||||
// * Protected by lock, so still valid.
|
||||
let data = unsafe { &*data };
|
||||
|
||||
ReadGuard { data, lock }
|
||||
}
|
||||
|
||||
fn update_seen(&self, seen_zero: &mut [bool; 2]) {
|
||||
for (seen, slot) in seen_zero.iter_mut().zip(&self.lock) {
|
||||
*seen = *seen || slot.load(Ordering::SeqCst) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
fn write_barrier(&self) {
|
||||
// Do a first check of seeing zeroes before we switch the generation. At least one of them
|
||||
// should be zero by now, due to having drained the generation before leaving the previous
|
||||
// writer.
|
||||
let mut seen_zero = [false; 2];
|
||||
self.update_seen(&mut seen_zero);
|
||||
// By switching the generation to the other slot, we make sure the currently active starts
|
||||
// draining while the other will start filling up.
|
||||
self.generation.fetch_add(1, Ordering::SeqCst); // Overflow is fine.
|
||||
|
||||
let mut iter = 0usize;
|
||||
while !seen_zero.iter().all(|s| *s) {
|
||||
iter = iter.wrapping_add(1);
|
||||
|
||||
// Be somewhat less aggressive while looping, switch to the other threads if possible.
|
||||
if cfg!(not(miri)) {
|
||||
if iter % YIELD_EVERY == 0 {
|
||||
thread::yield_now();
|
||||
} else {
|
||||
// Replaced by hint::spin_loop, but we want to support older compiler
|
||||
#[allow(deprecated)]
|
||||
atomic::spin_loop_hint();
|
||||
}
|
||||
}
|
||||
|
||||
self.update_seen(&mut seen_zero);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn write(&self) -> WriteGuard<T> {
|
||||
// While it's possible the user code panics, our code in store doesn't and the data gets
|
||||
// swapped atomically. So if it panics, nothing gets changed, therefore poisons are of no
|
||||
// interest here.
|
||||
let guard = self
|
||||
.write_mutex
|
||||
.lock()
|
||||
.unwrap_or_else(PoisonError::into_inner);
|
||||
|
||||
// Relaxed should be enough, as we are under the same mutex that was used to get the data
|
||||
// in.
|
||||
let data = self.data.load(Ordering::SeqCst);
|
||||
// Safe:
|
||||
// * Stored as valid data
|
||||
// * Only this method, protected by mutex, can change the pointer, so it didn't go away.
|
||||
let data = unsafe { &*data };
|
||||
|
||||
WriteGuard {
|
||||
data,
|
||||
_guard: guard,
|
||||
lock: self,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Drop for HalfLock<T> {
|
||||
fn drop(&mut self) {
|
||||
// During drop we are sure there are no other borrows of the data so we are free to just
|
||||
// drop it. Also, the drop impl won't be called in practice in our case, as it is used
|
||||
// solely as a global variable, but we provide it for completeness and tests anyway.
|
||||
//
|
||||
// unsafe: the pointer in there is always valid, we just take the last instance out.
|
||||
unsafe {
|
||||
// Acquire should be enough.
|
||||
let data = Box::from_raw(self.data.load(Ordering::SeqCst));
|
||||
drop(data);
|
||||
}
|
||||
}
|
||||
}
|
789
third_party/rust/signal-hook-registry/src/lib.rs
vendored
789
third_party/rust/signal-hook-registry/src/lib.rs
vendored
@ -1,789 +0,0 @@
|
||||
#![doc(test(attr(deny(warnings))))]
|
||||
#![warn(missing_docs)]
|
||||
#![allow(unknown_lints, renamed_and_remove_lints, bare_trait_objects)]
|
||||
|
||||
//! Backend of the [signal-hook] crate.
|
||||
//!
|
||||
//! The [signal-hook] crate tries to provide an API to the unix signals, which are a global
|
||||
//! resource. Therefore, it is desirable an application contains just one version of the crate
|
||||
//! which manages this global resource. But that makes it impossible to make breaking changes in
|
||||
//! the API.
|
||||
//!
|
||||
//! Therefore, this crate provides very minimal and low level API to the signals that is unlikely
|
||||
//! to have to change, while there may be multiple versions of the [signal-hook] that all use this
|
||||
//! low-level API to provide different versions of the high level APIs.
|
||||
//!
|
||||
//! It is also possible some other crates might want to build a completely different API. This
|
||||
//! split allows these crates to still reuse the same low-level routines in this crate instead of
|
||||
//! going to the (much more dangerous) unix calls.
|
||||
//!
|
||||
//! # What this crate provides
|
||||
//!
|
||||
//! The only thing this crate does is multiplexing the signals. An application or library can add
|
||||
//! or remove callbacks and have multiple callbacks for the same signal.
|
||||
//!
|
||||
//! It handles dispatching the callbacks and managing them in a way that uses only the
|
||||
//! [async-signal-safe] functions inside the signal handler. Note that the callbacks are still run
|
||||
//! inside the signal handler, so it is up to the caller to ensure they are also
|
||||
//! [async-signal-safe].
|
||||
//!
|
||||
//! # What this is for
|
||||
//!
|
||||
//! This is a building block for other libraries creating reasonable abstractions on top of
|
||||
//! signals. The [signal-hook] is the generally preferred way if you need to handle signals in your
|
||||
//! application and provides several safe patterns of doing so.
|
||||
//!
|
||||
//! # Rust version compatibility
|
||||
//!
|
||||
//! Currently builds on 1.26.0 an newer and this is very unlikely to change. However, tests
|
||||
//! require dependencies that don't build there, so tests need newer Rust version (they are run on
|
||||
//! stable).
|
||||
//!
|
||||
//! # Portability
|
||||
//!
|
||||
//! This crate includes a limited support for Windows, based on `signal`/`raise` in the CRT.
|
||||
//! There are differences in both API and behavior:
|
||||
//!
|
||||
//! - Due to lack of `siginfo_t`, we don't provide `register_sigaction` or `register_unchecked`.
|
||||
//! - 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.
|
||||
//!
|
||||
//! [signal-hook]: https://docs.rs/signal-hook
|
||||
//! [async-signal-safe]: http://www.man7.org/linux/man-pages/man7/signal-safety.7.html
|
||||
|
||||
extern crate libc;
|
||||
|
||||
mod half_lock;
|
||||
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::io::Error;
|
||||
use std::mem;
|
||||
#[cfg(not(windows))]
|
||||
use std::ptr;
|
||||
// Once::new is now a const-fn. But it is not stable in all the rustc versions we want to support
|
||||
// yet.
|
||||
#[allow(deprecated)]
|
||||
use std::sync::ONCE_INIT;
|
||||
use std::sync::{Arc, Once};
|
||||
|
||||
#[cfg(not(windows))]
|
||||
use libc::{c_int, c_void, sigaction, siginfo_t};
|
||||
#[cfg(windows)]
|
||||
use libc::{c_int, sighandler_t};
|
||||
|
||||
#[cfg(not(windows))]
|
||||
use libc::{SIGFPE, SIGILL, SIGKILL, SIGSEGV, SIGSTOP};
|
||||
#[cfg(windows)]
|
||||
use libc::{SIGFPE, SIGILL, SIGSEGV};
|
||||
|
||||
use half_lock::HalfLock;
|
||||
|
||||
// These constants are not defined in the current version of libc, but it actually
|
||||
// exists in Windows CRT.
|
||||
#[cfg(windows)]
|
||||
const SIG_DFL: sighandler_t = 0;
|
||||
#[cfg(windows)]
|
||||
const SIG_IGN: sighandler_t = 1;
|
||||
#[cfg(windows)]
|
||||
const SIG_GET: sighandler_t = 2;
|
||||
#[cfg(windows)]
|
||||
const SIG_ERR: sighandler_t = !0;
|
||||
|
||||
// To simplify implementation. Not to be exposed.
|
||||
#[cfg(windows)]
|
||||
#[allow(non_camel_case_types)]
|
||||
struct siginfo_t;
|
||||
|
||||
// # Internal workings
|
||||
//
|
||||
// This uses a form of RCU. There's an atomic pointer to the current action descriptors (in the
|
||||
// form of IndependentArcSwap, to be able to track what, if any, signal handlers still use the
|
||||
// version). A signal handler takes a copy of the pointer and calls all the relevant actions.
|
||||
//
|
||||
// Modifications to that are protected by a mutex, to avoid juggling multiple signal handlers at
|
||||
// once (eg. not calling sigaction concurrently). This should not be a problem, because modifying
|
||||
// the signal actions should be initialization only anyway. To avoid all allocations and also
|
||||
// deallocations inside the signal handler, after replacing the pointer, the modification routine
|
||||
// needs to busy-wait for the reference count on the old pointer to drop to 1 and take ownership ‒
|
||||
// that way the one deallocating is the modification routine, outside of the signal handler.
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
struct ActionId(u128);
|
||||
|
||||
/// An ID of registered action.
|
||||
///
|
||||
/// This is returned by all the registration routines and can be used to remove the action later on
|
||||
/// with a call to [`unregister`].
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
pub struct SigId {
|
||||
signal: c_int,
|
||||
action: ActionId,
|
||||
}
|
||||
|
||||
// This should be dyn Fn(...), but we want to support Rust 1.26.0 and that one doesn't allow dyn
|
||||
// yet.
|
||||
#[allow(unknown_lints, bare_trait_objects)]
|
||||
type Action = Fn(&siginfo_t) + Send + Sync;
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Slot {
|
||||
prev: Prev,
|
||||
// We use BTreeMap here, because we want to run the actions in the order they were inserted.
|
||||
// This works, because the ActionIds are assigned in an increasing order.
|
||||
actions: BTreeMap<ActionId, Arc<Action>>,
|
||||
}
|
||||
|
||||
impl Slot {
|
||||
#[cfg(windows)]
|
||||
fn new(signal: libc::c_int) -> Result<Self, Error> {
|
||||
let old = unsafe { libc::signal(signal, handler as sighandler_t) };
|
||||
if old == SIG_ERR {
|
||||
return Err(Error::last_os_error());
|
||||
}
|
||||
Ok(Slot {
|
||||
prev: Prev { signal, info: old },
|
||||
actions: BTreeMap::new(),
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
fn new(signal: libc::c_int) -> Result<Self, Error> {
|
||||
// C data structure, expected to be zeroed out.
|
||||
let mut new: libc::sigaction = unsafe { mem::zeroed() };
|
||||
#[cfg(not(target_os = "aix"))]
|
||||
{ new.sa_sigaction = handler as usize; }
|
||||
#[cfg(target_os = "aix")]
|
||||
{ new.sa_union.__su_sigaction = handler; }
|
||||
// Android is broken and uses different int types than the rest (and different depending on
|
||||
// the pointer width). This converts the flags to the proper type no matter what it is on
|
||||
// the given platform.
|
||||
let flags = libc::SA_RESTART;
|
||||
#[allow(unused_assignments)]
|
||||
let mut siginfo = flags;
|
||||
siginfo = libc::SA_SIGINFO as _;
|
||||
let flags = flags | siginfo;
|
||||
new.sa_flags = flags as _;
|
||||
// C data structure, expected to be zeroed out.
|
||||
let mut old: libc::sigaction = unsafe { mem::zeroed() };
|
||||
// FFI ‒ pointers are valid, it doesn't take ownership.
|
||||
if unsafe { libc::sigaction(signal, &new, &mut old) } != 0 {
|
||||
return Err(Error::last_os_error());
|
||||
}
|
||||
Ok(Slot {
|
||||
prev: Prev { signal, info: old },
|
||||
actions: BTreeMap::new(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct SignalData {
|
||||
signals: HashMap<c_int, Slot>,
|
||||
next_id: u128,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Prev {
|
||||
signal: c_int,
|
||||
#[cfg(windows)]
|
||||
info: sighandler_t,
|
||||
#[cfg(not(windows))]
|
||||
info: sigaction,
|
||||
}
|
||||
|
||||
impl Prev {
|
||||
#[cfg(windows)]
|
||||
fn detect(signal: c_int) -> Result<Self, Error> {
|
||||
let old = unsafe { libc::signal(signal, SIG_GET) };
|
||||
if old == SIG_ERR {
|
||||
return Err(Error::last_os_error());
|
||||
}
|
||||
Ok(Prev { signal, info: old })
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
fn detect(signal: c_int) -> Result<Self, Error> {
|
||||
// C data structure, expected to be zeroed out.
|
||||
let mut old: libc::sigaction = unsafe { mem::zeroed() };
|
||||
// FFI ‒ pointers are valid, it doesn't take ownership.
|
||||
if unsafe { libc::sigaction(signal, ptr::null(), &mut old) } != 0 {
|
||||
return Err(Error::last_os_error());
|
||||
}
|
||||
|
||||
Ok(Prev { signal, info: old })
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn execute(&self, sig: c_int) {
|
||||
let fptr = self.info;
|
||||
if fptr != 0 && fptr != SIG_DFL && fptr != SIG_IGN {
|
||||
// FFI ‒ calling the original signal handler.
|
||||
unsafe {
|
||||
let action = mem::transmute::<usize, extern "C" fn(c_int)>(fptr);
|
||||
action(sig);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
unsafe fn execute(&self, sig: c_int, info: *mut siginfo_t, data: *mut c_void) {
|
||||
#[cfg(not(target_os = "aix"))]
|
||||
let fptr = self.info.sa_sigaction;
|
||||
#[cfg(target_os = "aix")]
|
||||
let fptr = self.info.sa_union.__su_sigaction as usize;
|
||||
if fptr != 0 && fptr != libc::SIG_DFL && fptr != libc::SIG_IGN {
|
||||
// Android is broken and uses different int types than the rest (and different
|
||||
// depending on the pointer width). This converts the flags to the proper type no
|
||||
// matter what it is on the given platform.
|
||||
//
|
||||
// The trick is to create the same-typed variable as the sa_flags first and then
|
||||
// set it to the proper value (does Rust have a way to copy a type in a different
|
||||
// way?)
|
||||
#[allow(unused_assignments)]
|
||||
let mut siginfo = self.info.sa_flags;
|
||||
siginfo = libc::SA_SIGINFO as _;
|
||||
if self.info.sa_flags & siginfo == 0 {
|
||||
let action = mem::transmute::<usize, extern "C" fn(c_int)>(fptr);
|
||||
action(sig);
|
||||
} else {
|
||||
type SigAction = extern "C" fn(c_int, *mut siginfo_t, *mut c_void);
|
||||
let action = mem::transmute::<usize, SigAction>(fptr);
|
||||
action(sig, info, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Lazy-initiated data structure with our global variables.
|
||||
///
|
||||
/// Used inside a structure to cut down on boilerplate code to lazy-initialize stuff. We don't dare
|
||||
/// use anything fancy like lazy-static or once-cell, since we are not sure they are
|
||||
/// async-signal-safe in their access. Our code uses the [Once], but only on the write end outside
|
||||
/// of signal handler. The handler assumes it has already been initialized.
|
||||
struct GlobalData {
|
||||
/// The data structure describing what needs to be run for each signal.
|
||||
data: HalfLock<SignalData>,
|
||||
|
||||
/// A fallback to fight/minimize a race condition during signal initialization.
|
||||
///
|
||||
/// See the comment inside [`register_unchecked_impl`].
|
||||
race_fallback: HalfLock<Option<Prev>>,
|
||||
}
|
||||
|
||||
static mut GLOBAL_DATA: Option<GlobalData> = None;
|
||||
#[allow(deprecated)]
|
||||
static GLOBAL_INIT: Once = ONCE_INIT;
|
||||
|
||||
impl GlobalData {
|
||||
fn get() -> &'static Self {
|
||||
unsafe { GLOBAL_DATA.as_ref().unwrap() }
|
||||
}
|
||||
fn ensure() -> &'static Self {
|
||||
GLOBAL_INIT.call_once(|| unsafe {
|
||||
GLOBAL_DATA = Some(GlobalData {
|
||||
data: HalfLock::new(SignalData {
|
||||
signals: HashMap::new(),
|
||||
next_id: 1,
|
||||
}),
|
||||
race_fallback: HalfLock::new(None),
|
||||
});
|
||||
});
|
||||
Self::get()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
extern "C" fn handler(sig: c_int) {
|
||||
if sig != SIGFPE {
|
||||
// Windows CRT `signal` resets handler every time, unless for SIGFPE.
|
||||
// Reregister the handler to retain maximal compatibility.
|
||||
// Problems:
|
||||
// - It's racy. But this is inevitably racy in Windows.
|
||||
// - Interacts poorly with handlers outside signal-hook-registry.
|
||||
let old = unsafe { libc::signal(sig, handler as sighandler_t) };
|
||||
if old == SIG_ERR {
|
||||
// MSDN doesn't describe which errors might occur,
|
||||
// but we can tell from the Linux manpage that
|
||||
// EINVAL (invalid signal number) is mostly the only case.
|
||||
// Therefore, this branch must not occur.
|
||||
// In any case we can do nothing useful in the signal handler,
|
||||
// so we're going to abort silently.
|
||||
unsafe {
|
||||
libc::abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let globals = GlobalData::get();
|
||||
let fallback = globals.race_fallback.read();
|
||||
let sigdata = globals.data.read();
|
||||
|
||||
if let Some(ref slot) = sigdata.signals.get(&sig) {
|
||||
slot.prev.execute(sig);
|
||||
|
||||
for action in slot.actions.values() {
|
||||
action(&siginfo_t);
|
||||
}
|
||||
} else if let Some(prev) = fallback.as_ref() {
|
||||
// In case we get called but don't have the slot for this signal set up yet, we are under
|
||||
// the race condition. We may have the old signal handler stored in the fallback
|
||||
// temporarily.
|
||||
if sig == prev.signal {
|
||||
prev.execute(sig);
|
||||
}
|
||||
// else -> probably should not happen, but races with other threads are possible so
|
||||
// better safe
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
extern "C" fn handler(sig: c_int, info: *mut siginfo_t, data: *mut c_void) {
|
||||
let globals = GlobalData::get();
|
||||
let fallback = globals.race_fallback.read();
|
||||
let sigdata = globals.data.read();
|
||||
|
||||
if let Some(slot) = sigdata.signals.get(&sig) {
|
||||
unsafe { slot.prev.execute(sig, info, data) };
|
||||
|
||||
let info = unsafe { info.as_ref() };
|
||||
let info = info.unwrap_or_else(|| {
|
||||
// The info being null seems to be illegal according to POSIX, but has been observed on
|
||||
// some probably broken platform. We can't do anything about that, that is just broken,
|
||||
// but we are not allowed to panic in a signal handler, so we are left only with simply
|
||||
// aborting. We try to write a message what happens, but using the libc stuff
|
||||
// (`eprintln` is not guaranteed to be async-signal-safe).
|
||||
unsafe {
|
||||
const MSG: &[u8] =
|
||||
b"Platform broken, got NULL as siginfo to signal handler. Aborting";
|
||||
libc::write(2, MSG.as_ptr() as *const _, MSG.len());
|
||||
libc::abort();
|
||||
}
|
||||
});
|
||||
|
||||
for action in slot.actions.values() {
|
||||
action(info);
|
||||
}
|
||||
} else if let Some(prev) = fallback.as_ref() {
|
||||
// In case we get called but don't have the slot for this signal set up yet, we are under
|
||||
// the race condition. We may have the old signal handler stored in the fallback
|
||||
// temporarily.
|
||||
if prev.signal == sig {
|
||||
unsafe { prev.execute(sig, info, data) };
|
||||
}
|
||||
// else -> probably should not happen, but races with other threads are possible so
|
||||
// better safe
|
||||
}
|
||||
}
|
||||
|
||||
/// List of forbidden signals.
|
||||
///
|
||||
/// Some signals are impossible to replace according to POSIX and some are so special that this
|
||||
/// library refuses to handle them (eg. SIGSEGV). The routines panic in case registering one of
|
||||
/// these signals is attempted.
|
||||
///
|
||||
/// See [`register`].
|
||||
pub const FORBIDDEN: &[c_int] = FORBIDDEN_IMPL;
|
||||
|
||||
#[cfg(windows)]
|
||||
const FORBIDDEN_IMPL: &[c_int] = &[SIGILL, SIGFPE, SIGSEGV];
|
||||
#[cfg(not(windows))]
|
||||
const FORBIDDEN_IMPL: &[c_int] = &[SIGKILL, SIGSTOP, SIGILL, SIGFPE, SIGSEGV];
|
||||
|
||||
/// Registers an arbitrary action for the given signal.
|
||||
///
|
||||
/// This makes sure there's a signal handler for the given signal. It then adds the action to the
|
||||
/// ones called each time the signal is delivered. If multiple actions are set for the same signal,
|
||||
/// all are called, in the order of registration.
|
||||
///
|
||||
/// If there was a previous signal handler for the given signal, it is chained ‒ it will be called
|
||||
/// as part of this library's signal handler, before any actions set through this function.
|
||||
///
|
||||
/// On success, the function returns an ID that can be used to remove the action again with
|
||||
/// [`unregister`].
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// If the signal is one of (see [`FORBIDDEN`]):
|
||||
///
|
||||
/// * `SIGKILL`
|
||||
/// * `SIGSTOP`
|
||||
/// * `SIGILL`
|
||||
/// * `SIGFPE`
|
||||
/// * `SIGSEGV`
|
||||
///
|
||||
/// The first two are not possible to override (and the underlying C functions simply ignore all
|
||||
/// requests to do so, which smells of possible bugs, or return errors). The rest can be set, but
|
||||
/// generally needs very special handling to do so correctly (direct manipulation of the
|
||||
/// application's address space, `longjmp` and similar). Unless you know very well what you're
|
||||
/// doing, you'll shoot yourself into the foot and this library won't help you with that.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Since the library manipulates signals using the low-level C functions, all these can return
|
||||
/// errors. Generally, the errors mean something like the specified signal does not exist on the
|
||||
/// given platform ‒ after a program is debugged and tested on a given OS, it should never return
|
||||
/// an error.
|
||||
///
|
||||
/// However, if an error *is* returned, there are no guarantees if the given action was registered
|
||||
/// or not.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is unsafe, because the `action` is run inside a signal handler. The set of
|
||||
/// functions allowed to be called from within is very limited (they are called async-signal-safe
|
||||
/// functions by POSIX). These specifically do *not* contain mutexes and memory
|
||||
/// allocation/deallocation. They *do* contain routines to terminate the program, to further
|
||||
/// manipulate signals (by the low-level functions, not by this library) and to read and write file
|
||||
/// descriptors. Calling program's own functions consisting only of these is OK, as is manipulating
|
||||
/// program's variables ‒ however, as the action can be called on any thread that does not have the
|
||||
/// given signal masked (by default no signal is masked on any thread), and mutexes are a no-go,
|
||||
/// this is harder than it looks like at first.
|
||||
///
|
||||
/// As panicking from within a signal handler would be a panic across FFI boundary (which is
|
||||
/// undefined behavior), the passed handler must not panic.
|
||||
///
|
||||
/// If you find these limitations hard to satisfy, choose from the helper functions in the
|
||||
/// [signal-hook](https://docs.rs/signal-hook) crate ‒ these provide safe interface to use some
|
||||
/// common signal handling patters.
|
||||
///
|
||||
/// # Race condition
|
||||
///
|
||||
/// Upon registering the first hook for a given signal into this library, there's a short race
|
||||
/// condition under the following circumstances:
|
||||
///
|
||||
/// * The program already has a signal handler installed for this particular signal (through some
|
||||
/// other library, possibly).
|
||||
/// * Concurrently, some other thread installs a different signal handler while it is being
|
||||
/// installed by this library.
|
||||
/// * At the same time, the signal is delivered.
|
||||
///
|
||||
/// Under such conditions signal-hook might wrongly "chain" to the older signal handler for a short
|
||||
/// while (until the registration is fully complete).
|
||||
///
|
||||
/// Note that the exact conditions of the race condition might change in future versions of the
|
||||
/// library. The recommended way to avoid it is to register signals before starting any additional
|
||||
/// threads, or at least not to register signals concurrently.
|
||||
///
|
||||
/// Alternatively, make sure all signals are handled through this library.
|
||||
///
|
||||
/// # Performance
|
||||
///
|
||||
/// Even when it is possible to repeatedly install and remove actions during the lifetime of a
|
||||
/// program, the installation and removal is considered a slow operation and should not be done
|
||||
/// very often. Also, there's limited (though huge) amount of distinct IDs (they are `u128`).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// extern crate signal_hook_registry;
|
||||
///
|
||||
/// use std::io::Error;
|
||||
/// use std::process;
|
||||
///
|
||||
/// fn main() -> Result<(), Error> {
|
||||
/// let signal = unsafe {
|
||||
/// signal_hook_registry::register(signal_hook::consts::SIGTERM, || process::abort())
|
||||
/// }?;
|
||||
/// // Stuff here...
|
||||
/// signal_hook_registry::unregister(signal); // Not really necessary.
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
pub unsafe fn register<F>(signal: c_int, action: F) -> Result<SigId, Error>
|
||||
where
|
||||
F: Fn() + Sync + Send + 'static,
|
||||
{
|
||||
register_sigaction_impl(signal, move |_: &_| action())
|
||||
}
|
||||
|
||||
/// Register a signal action.
|
||||
///
|
||||
/// This acts in the same way as [`register`], including the drawbacks, panics and performance
|
||||
/// characteristics. The only difference is the provided action accepts a [`siginfo_t`] argument,
|
||||
/// providing information about the received signal.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// See the details of [`register`].
|
||||
#[cfg(not(windows))]
|
||||
pub unsafe fn register_sigaction<F>(signal: c_int, action: F) -> Result<SigId, Error>
|
||||
where
|
||||
F: Fn(&siginfo_t) + Sync + Send + 'static,
|
||||
{
|
||||
register_sigaction_impl(signal, action)
|
||||
}
|
||||
|
||||
unsafe fn register_sigaction_impl<F>(signal: c_int, action: F) -> Result<SigId, Error>
|
||||
where
|
||||
F: Fn(&siginfo_t) + Sync + Send + 'static,
|
||||
{
|
||||
assert!(
|
||||
!FORBIDDEN.contains(&signal),
|
||||
"Attempted to register forbidden signal {}",
|
||||
signal,
|
||||
);
|
||||
register_unchecked_impl(signal, action)
|
||||
}
|
||||
|
||||
/// Register a signal action without checking for forbidden signals.
|
||||
///
|
||||
/// This acts in the same way as [`register_unchecked`], including the drawbacks, panics and
|
||||
/// performance characteristics. The only difference is the provided action doesn't accept a
|
||||
/// [`siginfo_t`] argument.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// See the details of [`register`].
|
||||
pub unsafe fn register_signal_unchecked<F>(signal: c_int, action: F) -> Result<SigId, Error>
|
||||
where
|
||||
F: Fn() + Sync + Send + 'static,
|
||||
{
|
||||
register_unchecked_impl(signal, move |_: &_| action())
|
||||
}
|
||||
|
||||
/// Register a signal action without checking for forbidden signals.
|
||||
///
|
||||
/// This acts the same way as [`register_sigaction`], but without checking for the [`FORBIDDEN`]
|
||||
/// signals. All the signals passed are registered and it is up to the caller to make some sense of
|
||||
/// them.
|
||||
///
|
||||
/// Note that you really need to know what you're doing if you change eg. the `SIGSEGV` signal
|
||||
/// handler. Generally, you don't want to do that. But unlike the other functions here, this
|
||||
/// function still allows you to do it.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// See the details of [`register`].
|
||||
#[cfg(not(windows))]
|
||||
pub unsafe fn register_unchecked<F>(signal: c_int, action: F) -> Result<SigId, Error>
|
||||
where
|
||||
F: Fn(&siginfo_t) + Sync + Send + 'static,
|
||||
{
|
||||
register_unchecked_impl(signal, action)
|
||||
}
|
||||
|
||||
unsafe fn register_unchecked_impl<F>(signal: c_int, action: F) -> Result<SigId, Error>
|
||||
where
|
||||
F: Fn(&siginfo_t) + Sync + Send + 'static,
|
||||
{
|
||||
let globals = GlobalData::ensure();
|
||||
let action = Arc::from(action);
|
||||
|
||||
let mut lock = globals.data.write();
|
||||
|
||||
let mut sigdata = SignalData::clone(&lock);
|
||||
let id = ActionId(sigdata.next_id);
|
||||
sigdata.next_id += 1;
|
||||
|
||||
match sigdata.signals.entry(signal) {
|
||||
Entry::Occupied(mut occupied) => {
|
||||
assert!(occupied.get_mut().actions.insert(id, action).is_none());
|
||||
}
|
||||
Entry::Vacant(place) => {
|
||||
// While the sigaction/signal exchanges the old one atomically, we are not able to
|
||||
// atomically store it somewhere a signal handler could read it. That poses a race
|
||||
// condition where we could lose some signals delivered in between changing it and
|
||||
// storing it.
|
||||
//
|
||||
// Therefore we first store the old one in the fallback storage. The fallback only
|
||||
// covers the cases where the slot is not yet active and becomes "inert" after that,
|
||||
// even if not removed (it may get overwritten by some other signal, but for that the
|
||||
// mutex in globals.data must be unlocked here - and by that time we already stored the
|
||||
// slot.
|
||||
//
|
||||
// And yes, this still leaves a short race condition when some other thread could
|
||||
// replace the signal handler and we would be calling the outdated one for a short
|
||||
// time, until we install the slot.
|
||||
globals
|
||||
.race_fallback
|
||||
.write()
|
||||
.store(Some(Prev::detect(signal)?));
|
||||
|
||||
let mut slot = Slot::new(signal)?;
|
||||
slot.actions.insert(id, action);
|
||||
place.insert(slot);
|
||||
}
|
||||
}
|
||||
|
||||
lock.store(sigdata);
|
||||
|
||||
Ok(SigId { signal, action: id })
|
||||
}
|
||||
|
||||
/// Removes a previously installed action.
|
||||
///
|
||||
/// This function does nothing if the action was already removed. It returns true if it was removed
|
||||
/// and false if the action wasn't found.
|
||||
///
|
||||
/// It can unregister all the actions installed by [`register`] as well as the ones from downstream
|
||||
/// crates (like [`signal-hook`](https://docs.rs/signal-hook)).
|
||||
///
|
||||
/// # Warning
|
||||
///
|
||||
/// This does *not* currently return the default/previous signal handler if the last action for a
|
||||
/// signal was just unregistered. That means that if you replaced for example `SIGTERM` and then
|
||||
/// removed the action, the program will effectively ignore `SIGTERM` signals from now on, not
|
||||
/// terminate on them as is the default action. This is OK if you remove it as part of a shutdown,
|
||||
/// but it is not recommended to remove termination actions during the normal runtime of
|
||||
/// application (unless the desired effect is to create something that can be terminated only by
|
||||
/// SIGKILL).
|
||||
pub fn unregister(id: SigId) -> bool {
|
||||
let globals = GlobalData::ensure();
|
||||
let mut replace = false;
|
||||
let mut lock = globals.data.write();
|
||||
let mut sigdata = SignalData::clone(&lock);
|
||||
if let Some(slot) = sigdata.signals.get_mut(&id.signal) {
|
||||
replace = slot.actions.remove(&id.action).is_some();
|
||||
}
|
||||
if replace {
|
||||
lock.store(sigdata);
|
||||
}
|
||||
replace
|
||||
}
|
||||
|
||||
// We keep this one here for strict backwards compatibility, but the API is kind of bad. One can
|
||||
// delete actions that don't belong to them, which is kind of against the whole idea of not
|
||||
// breaking stuff for others.
|
||||
#[deprecated(
|
||||
since = "1.3.0",
|
||||
note = "Don't use. Can influence unrelated parts of program / unknown actions"
|
||||
)]
|
||||
#[doc(hidden)]
|
||||
pub fn unregister_signal(signal: c_int) -> bool {
|
||||
let globals = GlobalData::ensure();
|
||||
let mut replace = false;
|
||||
let mut lock = globals.data.write();
|
||||
let mut sigdata = SignalData::clone(&lock);
|
||||
if let Some(slot) = sigdata.signals.get_mut(&signal) {
|
||||
if !slot.actions.is_empty() {
|
||||
slot.actions.clear();
|
||||
replace = true;
|
||||
}
|
||||
}
|
||||
if replace {
|
||||
lock.store(sigdata);
|
||||
}
|
||||
replace
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
#[cfg(not(windows))]
|
||||
use libc::{pid_t, SIGUSR1, SIGUSR2};
|
||||
|
||||
#[cfg(windows)]
|
||||
use libc::SIGTERM as SIGUSR1;
|
||||
#[cfg(windows)]
|
||||
use libc::SIGTERM as SIGUSR2;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn panic_forbidden() {
|
||||
let _ = unsafe { register(SIGILL, || ()) };
|
||||
}
|
||||
|
||||
/// Registering the forbidden signals is allowed in the _unchecked version.
|
||||
#[test]
|
||||
#[allow(clippy::redundant_closure)] // Clippy, you're wrong. Because it changes the return value.
|
||||
fn forbidden_raw() {
|
||||
unsafe { register_signal_unchecked(SIGFPE, || std::process::abort()).unwrap() };
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn signal_without_pid() {
|
||||
let status = Arc::new(AtomicUsize::new(0));
|
||||
let action = {
|
||||
let status = Arc::clone(&status);
|
||||
move || {
|
||||
status.store(1, Ordering::Relaxed);
|
||||
}
|
||||
};
|
||||
unsafe {
|
||||
register(SIGUSR2, action).unwrap();
|
||||
libc::raise(SIGUSR2);
|
||||
}
|
||||
for _ in 0..10 {
|
||||
thread::sleep(Duration::from_millis(100));
|
||||
let current = status.load(Ordering::Relaxed);
|
||||
match current {
|
||||
// Not yet
|
||||
0 => continue,
|
||||
// Good, we are done with the correct result
|
||||
_ if current == 1 => return,
|
||||
_ => panic!("Wrong result value {}", current),
|
||||
}
|
||||
}
|
||||
panic!("Timed out waiting for the signal");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(windows))]
|
||||
fn signal_with_pid() {
|
||||
let status = Arc::new(AtomicUsize::new(0));
|
||||
let action = {
|
||||
let status = Arc::clone(&status);
|
||||
move |siginfo: &siginfo_t| {
|
||||
// Hack: currently, libc exposes only the first 3 fields of siginfo_t. The pid
|
||||
// comes somewhat later on. Therefore, we do a Really Ugly Hack and define our
|
||||
// own structure (and hope it is correct on all platforms). But hey, this is
|
||||
// only the tests, so we are going to get away with this.
|
||||
#[repr(C)]
|
||||
struct SigInfo {
|
||||
_fields: [c_int; 3],
|
||||
#[cfg(all(target_pointer_width = "64", target_os = "linux"))]
|
||||
_pad: c_int,
|
||||
pid: pid_t,
|
||||
}
|
||||
let s: &SigInfo = unsafe {
|
||||
(siginfo as *const _ as usize as *const SigInfo)
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
};
|
||||
status.store(s.pid as usize, Ordering::Relaxed);
|
||||
}
|
||||
};
|
||||
let pid;
|
||||
unsafe {
|
||||
pid = libc::getpid();
|
||||
register_sigaction(SIGUSR2, action).unwrap();
|
||||
libc::raise(SIGUSR2);
|
||||
}
|
||||
for _ in 0..10 {
|
||||
thread::sleep(Duration::from_millis(100));
|
||||
let current = status.load(Ordering::Relaxed);
|
||||
match current {
|
||||
// Not yet (PID == 0 doesn't happen)
|
||||
0 => continue,
|
||||
// Good, we are done with the correct result
|
||||
_ if current == pid as usize => return,
|
||||
_ => panic!("Wrong status value {}", current),
|
||||
}
|
||||
}
|
||||
panic!("Timed out waiting for the signal");
|
||||
}
|
||||
|
||||
/// Check that registration works as expected and that unregister tells if it did or not.
|
||||
#[test]
|
||||
fn register_unregister() {
|
||||
let signal = unsafe { register(SIGUSR1, || ()).unwrap() };
|
||||
// It was there now, so we can unregister
|
||||
assert!(unregister(signal));
|
||||
// The next time unregistering does nothing and tells us so.
|
||||
assert!(!unregister(signal));
|
||||
}
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
//! Tests for the [unregister_signal] function.
|
||||
//!
|
||||
//! As a separate integration level test, so it doesn't clash with other tests on the signals.
|
||||
|
||||
// The unregister_signal itself is deprecated. But we still want to test it, so it's not deprecated
|
||||
// and broken at the same time.
|
||||
#![allow(deprecated)]
|
||||
|
||||
extern crate libc;
|
||||
extern crate signal_hook_registry;
|
||||
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::sync::Arc;
|
||||
|
||||
use libc::{SIGINT, SIGTERM}; // We'll use these here because SIGUSR1 is not available on Windows.
|
||||
use signal_hook_registry::{register, unregister_signal};
|
||||
|
||||
#[test]
|
||||
fn register_unregister() {
|
||||
let called = Arc::new(AtomicUsize::new(0));
|
||||
|
||||
let hook = {
|
||||
let called = Arc::clone(&called);
|
||||
move || {
|
||||
called.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
};
|
||||
|
||||
unsafe {
|
||||
register(SIGTERM, hook.clone()).unwrap();
|
||||
register(SIGTERM, hook.clone()).unwrap();
|
||||
register(SIGINT, hook.clone()).unwrap();
|
||||
|
||||
libc::raise(SIGTERM);
|
||||
}
|
||||
|
||||
// The closure is run twice.
|
||||
assert_eq!(2, called.load(Ordering::Relaxed));
|
||||
|
||||
assert!(unregister_signal(SIGTERM));
|
||||
|
||||
unsafe { libc::raise(SIGTERM) };
|
||||
// Second one unregisters nothing.
|
||||
assert!(!unregister_signal(SIGTERM));
|
||||
|
||||
// After unregistering (both), it is no longer run at all.
|
||||
assert_eq!(2, called.load(Ordering::Relaxed));
|
||||
|
||||
// The SIGINT one is not disturbed.
|
||||
unsafe { libc::raise(SIGINT) };
|
||||
assert_eq!(3, called.load(Ordering::Relaxed));
|
||||
|
||||
// But it's possible to register it again just fine.
|
||||
unsafe {
|
||||
register(SIGTERM, hook).unwrap();
|
||||
libc::raise(SIGTERM);
|
||||
}
|
||||
assert_eq!(4, called.load(Ordering::Relaxed));
|
||||
}
|
Loading…
Reference in New Issue
Block a user