10 Commits

Author SHA1 Message Date
9cfd407f16 Merge 7a943ebba6 into 40f835afd2 2025-01-18 12:11:35 +01:00
7a943ebba6 Fix clippy issues 2025-01-18 12:11:26 +01:00
25ae542ade Add support for LazyLock 2025-01-18 11:59:18 +01:00
40f835afd2 Fix clippy issues 2025-01-18 11:57:47 +01:00
e60dba2c25 Move MSRV checking to a separate step 2025-01-18 11:57:47 +01:00
8b69ba7835 Update to actions/checkout v4 2025-01-18 11:57:47 +01:00
9ca5af2c82 Merge pull request #36 from bertptrs/example/show-potential 2023-11-13 08:37:36 +01:00
74b4fe0bb1 Rewrite example to show potential deadlock
The example originally showed a certain deadlock, which was not as clear
as it could be. The new version shows intentionally racy code that may
result in a successful execution but may also deadlock.
2023-11-12 18:36:53 +01:00
bors[bot]
6199598944 Merge #34
34: Fix remaining references to TracingMutex r=bertptrs a=bertptrs

Thanks to `@ReinierMaas` for noticing.

Co-authored-by: Bert Peters <bert@bertptrs.nl>
2023-10-06 07:01:48 +00:00
fd75fc453b Fix remaining references to TracingMutex 2023-10-06 08:59:21 +02:00
13 changed files with 1057 additions and 46 deletions

View File

@@ -15,30 +15,43 @@ jobs:
strategy: strategy:
matrix: matrix:
rust: rust:
- "1.70" # minimum stable rust version
- stable - stable
- beta - beta
- nightly - nightly
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@v1 - uses: dtolnay/rust-toolchain@v1
with: with:
toolchain: ${{ matrix.rust }} toolchain: ${{ matrix.rust }}
components: rustfmt, clippy components: rustfmt, clippy
# Make sure we test with recent deps
- run: cargo update
- run: cargo build --all-features --all-targets - run: cargo build --all-features --all-targets
- run: cargo test --all-features - run: cargo test --all-features
- run: cargo fmt --all -- --check - run: cargo fmt --all -- --check
- run: cargo clippy --all-features --all-targets -- -D warnings - run: cargo clippy --all-features --all-targets -- -D warnings
msrv:
name: MSRV
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@v1
with:
toolchain: "1.70"
- run: cargo test --all-features
docs: docs:
name: Documentation build name: Documentation build
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@v1 - uses: dtolnay/rust-toolchain@v1
with: with:

1
.gitignore vendored
View File

@@ -1,2 +1 @@
/target /target
Cargo.lock

View File

@@ -6,6 +6,10 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased] ## [Unreleased]
### Changed
- Reworked CI to better test continued support for the minimum supported Rust version
## [0.3.0] - 2023-09-09 ## [0.3.0] - 2023-09-09
### Added ### Added

810
Cargo.lock generated Normal file
View File

@@ -0,0 +1,810 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "aho-corasick"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6748e8def348ed4d14996fa801f4122cd763fff530258cdc03f64b25f89d3a5a"
dependencies = [
"memchr",
]
[[package]]
name = "anes"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
[[package]]
name = "anstyle"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15c4c2c83f81532e5845a733998b6971faca23490340a418e9b72a3ec9de12ea"
[[package]]
name = "autocfg"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
[[package]]
name = "bumpalo"
version = "3.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
[[package]]
name = "cast"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
[[package]]
name = "cc"
version = "1.0.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
dependencies = [
"libc",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "ciborium"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926"
dependencies = [
"ciborium-io",
"ciborium-ll",
"serde",
]
[[package]]
name = "ciborium-io"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656"
[[package]]
name = "ciborium-ll"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b"
dependencies = [
"ciborium-io",
"half",
]
[[package]]
name = "clap"
version = "4.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d5f1946157a96594eb2d2c10eb7ad9a2b27518cb3000209dec700c35df9197d"
dependencies = [
"clap_builder",
]
[[package]]
name = "clap_builder"
version = "4.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78116e32a042dd73c2901f0dc30790d20ff3447f3e3472fad359e8c3d282bcd6"
dependencies = [
"anstyle",
"clap_lex",
]
[[package]]
name = "clap_lex"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961"
[[package]]
name = "criterion"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f"
dependencies = [
"anes",
"cast",
"ciborium",
"clap",
"criterion-plot",
"is-terminal",
"itertools",
"num-traits",
"once_cell",
"oorandom",
"plotters",
"rayon",
"regex",
"serde",
"serde_derive",
"serde_json",
"tinytemplate",
"walkdir",
]
[[package]]
name = "criterion-plot"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1"
dependencies = [
"cast",
"itertools",
]
[[package]]
name = "crossbeam-channel"
version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200"
dependencies = [
"cfg-if",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-deque"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
dependencies = [
"cfg-if",
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7"
dependencies = [
"autocfg",
"cfg-if",
"crossbeam-utils",
"memoffset",
"scopeguard",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294"
dependencies = [
"cfg-if",
]
[[package]]
name = "either"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
[[package]]
name = "errno"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f"
dependencies = [
"errno-dragonfly",
"libc",
"windows-sys",
]
[[package]]
name = "errno-dragonfly"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
dependencies = [
"cc",
"libc",
]
[[package]]
name = "getrandom"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "half"
version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
[[package]]
name = "hermit-abi"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
[[package]]
name = "is-terminal"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
dependencies = [
"hermit-abi",
"rustix",
"windows-sys",
]
[[package]]
name = "itertools"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
[[package]]
name = "js-sys"
version = "0.3.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a"
dependencies = [
"wasm-bindgen",
]
[[package]]
name = "libc"
version = "0.2.147"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
[[package]]
name = "linux-raw-sys"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503"
[[package]]
name = "lock_api"
version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16"
dependencies = [
"autocfg",
"scopeguard",
]
[[package]]
name = "log"
version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
[[package]]
name = "memchr"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "memoffset"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
dependencies = [
"autocfg",
]
[[package]]
name = "num-traits"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2"
dependencies = [
"autocfg",
]
[[package]]
name = "num_cpus"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
dependencies = [
"hermit-abi",
"libc",
]
[[package]]
name = "once_cell"
version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]]
name = "oorandom"
version = "11.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
[[package]]
name = "parking_lot"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
dependencies = [
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"windows-targets",
]
[[package]]
name = "plotters"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45"
dependencies = [
"num-traits",
"plotters-backend",
"plotters-svg",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "plotters-backend"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609"
[[package]]
name = "plotters-svg"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab"
dependencies = [
"plotters-backend",
]
[[package]]
name = "ppv-lite86"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "proc-macro2"
version = "1.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]]
name = "rayon"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b"
dependencies = [
"either",
"rayon-core",
]
[[package]]
name = "rayon-core"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d"
dependencies = [
"crossbeam-channel",
"crossbeam-deque",
"crossbeam-utils",
"num_cpus",
]
[[package]]
name = "redox_syscall"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
dependencies = [
"bitflags 1.3.2",
]
[[package]]
name = "regex"
version = "1.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12de2eff854e5fa4b1295edd650e227e9d8fb0c9e90b12e7f36d6a6811791a29"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49530408a136e16e5b486e883fbb6ba058e8e4e8ae6621a77b048b314336e629"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da"
[[package]]
name = "rustix"
version = "0.38.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9bfe0f2582b4931a45d1fa608f8a8722e8b3c7ac54dd6d5f3b3212791fedef49"
dependencies = [
"bitflags 2.4.0",
"errno",
"libc",
"linux-raw-sys",
"windows-sys",
]
[[package]]
name = "ryu"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "serde"
version = "1.0.188"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.188"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "smallvec"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
[[package]]
name = "syn"
version = "2.0.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "tinytemplate"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc"
dependencies = [
"serde",
"serde_json",
]
[[package]]
name = "tracing-mutex"
version = "0.3.0"
dependencies = [
"autocfg",
"criterion",
"lock_api",
"parking_lot",
"rand",
]
[[package]]
name = "unicode-ident"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
[[package]]
name = "walkdir"
version = "2.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698"
dependencies = [
"same-file",
"winapi-util",
]
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm-bindgen"
version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd"
dependencies = [
"bumpalo",
"log",
"once_cell",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
dependencies = [
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
[[package]]
name = "web-sys"
version = "0.3.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[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-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"

View File

@@ -36,3 +36,6 @@ backtraces = []
# Feature names do not match crate names pending namespaced features. # Feature names do not match crate names pending namespaced features.
lockapi = ["lock_api"] lockapi = ["lock_api"]
parkinglot = ["parking_lot", "lockapi"] parkinglot = ["parking_lot", "lockapi"]
[build-dependencies]
autocfg = "1.4.0"

View File

@@ -56,10 +56,10 @@ introduce a cyclic dependency between your locks, the operation panics instead.
immediately notice the cyclic dependency rather than be eventually surprised by it in production. immediately notice the cyclic dependency rather than be eventually surprised by it in production.
Mutex tracing is efficient, but it is not completely overhead-free. If you cannot spare the Mutex tracing is efficient, but it is not completely overhead-free. If you cannot spare the
performance penalty in your production environment, this library also offers debug-only tracing. performance penalty in your production environment, this library also offers debug-only tracing. The
`DebugMutex`, also found in the `stdsync` module, is a type alias that evaluates to `TracingMutex` type aliases in `tracing_mutex::stdsync` correspond to tracing primitives from
when debug assertions are enabled, and to `Mutex` when they are not. Similar helper types are `tracing_mutex::stdsync::tracing` when debug assertions are enabled, and to primitives from
available for other synchronization primitives. `std::sync::Mutex` when they are not. A similar structure exists for other
The minimum supported Rust version is 1.70. Increasing this is not considered a breaking change, but The minimum supported Rust version is 1.70. Increasing this is not considered a breaking change, but
will be avoided within semver-compatible releases if possible. will be avoided within semver-compatible releases if possible.
@@ -68,6 +68,7 @@ will be avoided within semver-compatible releases if possible.
- Dependency-tracking wrappers for all locking primitives - Dependency-tracking wrappers for all locking primitives
- Optional opt-out for release mode code - Optional opt-out for release mode code
- Optional backtrace capture to aid with reproducing cyclic mutex chains
- Support for primitives from: - Support for primitives from:
- `std::sync` - `std::sync`
- `parking_lot` - `parking_lot`
@@ -76,7 +77,6 @@ will be avoided within semver-compatible releases if possible.
## Future improvements ## Future improvements
- Improve performance in lock tracing - Improve performance in lock tracing
- Optional logging to make debugging easier
- Better and configurable error handling when detecting cyclic dependencies - Better and configurable error handling when detecting cyclic dependencies
- Support for other locking libraries - Support for other locking libraries
- Support for async locking libraries - Support for async locking libraries

10
build.rs Normal file
View File

@@ -0,0 +1,10 @@
use autocfg::AutoCfg;
fn main() {
// To avoid bumping MSRV unnecessarily, we can sniff certain features. Reevaluate this on major
// releases.
let ac = AutoCfg::new().unwrap();
ac.emit_has_path("std::sync::LazyLock");
autocfg::rerun_path("build.rs");
}

View File

@@ -1,26 +1,62 @@
//! Show what a crash looks like //! Show what a crash looks like
//! //!
//! This shows what a traceback of a cycle detection looks like. It is expected to crash. //! This shows what a traceback of a cycle detection looks like. It is expected to crash when run in
//! debug mode, because it might deadlock. In release mode, no tracing is used and the program may
//! do any of the following:
//!
//! - Return a random valuation of `a`, `b`, and `c`. The implementation has a race-condition by
//! design. I have observed (4, 3, 6), but also (6, 3, 5).
//! - Deadlock forever.
//!
//! One can increase the SLEEP_TIME constant to increase the likelihood of a deadlock to occur. On
//! my machine, 1ns of sleep time gives about a 50/50 chance of the program deadlocking.
use std::thread;
use std::time::Duration;
use tracing_mutex::stdsync::Mutex; use tracing_mutex::stdsync::Mutex;
fn main() { fn main() {
let a = Mutex::new(()); let a = Mutex::new(1);
let b = Mutex::new(()); let b = Mutex::new(2);
let c = Mutex::new(()); let c = Mutex::new(3);
// Create an edge from a to b // Increase this time to increase the likelihood of a deadlock.
{ const SLEEP_TIME: Duration = Duration::from_nanos(1);
let _a = a.lock();
let _b = b.lock();
}
// Create an edge from b to c // Depending on random CPU performance, this section may deadlock, or may return a result. With
{ // tracing enabled, the potential deadlock is always detected and a backtrace should be
let _b = b.lock(); // produced.
let _c = c.lock(); thread::scope(|s| {
} // Create an edge from a to b
s.spawn(|| {
let a = a.lock().unwrap();
thread::sleep(SLEEP_TIME);
*b.lock().unwrap() += *a;
});
// Now crash by trying to add an edge from c to a // Create an edge from b to c
let _c = c.lock(); s.spawn(|| {
let _a = a.lock(); // This line will crash let b = b.lock().unwrap();
thread::sleep(SLEEP_TIME);
*c.lock().unwrap() += *b;
});
// Create an edge from c to a
//
// N.B. the program can crash on any of the three edges, as there is no guarantee which
// thread will execute first. Nevertheless, any one of them is guaranteed to panic with
// tracing enabled.
s.spawn(|| {
let c = c.lock().unwrap();
thread::sleep(SLEEP_TIME);
*a.lock().unwrap() += *c;
});
});
println!(
"{}, {}, {}",
a.into_inner().unwrap(),
b.into_inner().unwrap(),
c.into_inner().unwrap()
);
} }

View File

@@ -105,7 +105,7 @@ thread_local! {
/// ///
/// Assuming that locks are roughly released in the reverse order in which they were acquired, /// Assuming that locks are roughly released in the reverse order in which they were acquired,
/// a stack should be more efficient to keep track of the current state than a set would be. /// a stack should be more efficient to keep track of the current state than a set would be.
static HELD_LOCKS: RefCell<Vec<usize>> = RefCell::new(Vec::new()); static HELD_LOCKS: RefCell<Vec<usize>> = const { RefCell::new(Vec::new()) };
} }
/// Dedicated ID type for Mutexes /// Dedicated ID type for Mutexes
@@ -193,6 +193,14 @@ impl MutexId {
unreachable!("Tried to drop lock for mutex {:?} but it wasn't held", self) unreachable!("Tried to drop lock for mutex {:?} but it wasn't held", self)
}); });
} }
/// Execute the given closure while the guard is held.
pub fn with_held<T>(&self, f: impl FnOnce() -> T) -> T {
// Note: we MUST construct the RAII guard, we cannot simply mark held + mark released, as
// f() may panic and corrupt our state.
let _guard = self.get_borrowed();
f()
}
} }
impl Default for MutexId { impl Default for MutexId {
@@ -275,7 +283,7 @@ struct BorrowedMutex<'a> {
/// ///
/// This function panics if the lock did not appear to be handled by this thread. If that happens, /// This function panics if the lock did not appear to be handled by this thread. If that happens,
/// that is an indication of a serious design flaw in this library. /// that is an indication of a serious design flaw in this library.
impl<'a> Drop for BorrowedMutex<'a> { impl Drop for BorrowedMutex<'_> {
fn drop(&mut self) { fn drop(&mut self) {
// Safety: the only way to get a BorrowedMutex is by locking the mutex. // Safety: the only way to get a BorrowedMutex is by locking the mutex.
unsafe { self.id.mark_released() }; unsafe { self.id.mark_released() };

View File

@@ -90,6 +90,8 @@ unsafe impl<T> RawMutex for TracingWrapper<T>
where where
T: RawMutex, T: RawMutex,
{ {
// Known issue with legacy initialisers, allow
#[allow(clippy::declare_interior_mutable_const)]
const INIT: Self = Self { const INIT: Self = Self {
inner: T::INIT, inner: T::INIT,
id: LazyMutexId::new(), id: LazyMutexId::new(),
@@ -154,6 +156,8 @@ unsafe impl<T> RawRwLock for TracingWrapper<T>
where where
T: RawRwLock, T: RawRwLock,
{ {
// Known issue with legacy initialisers, allow
#[allow(clippy::declare_interior_mutable_const)]
const INIT: Self = Self { const INIT: Self = Self {
inner: T::INIT, inner: T::INIT,
id: LazyMutexId::new(), id: LazyMutexId::new(),

View File

@@ -138,16 +138,14 @@ pub mod tracing {
/// This method will panic if `f` panics, poisoning this `Once`. In addition, this function /// This method will panic if `f` panics, poisoning this `Once`. In addition, this function
/// panics when the lock acquisition order is determined to be inconsistent. /// panics when the lock acquisition order is determined to be inconsistent.
pub fn call_once(&self, f: impl FnOnce()) { pub fn call_once(&self, f: impl FnOnce()) {
let _borrow = self.id.get_borrowed(); self.id.with_held(|| self.inner.call_once(f));
self.inner.call_once(f);
} }
/// Performs the given initialization routine once and only once. /// Performs the given initialization routine once and only once.
/// ///
/// This method is identical to [`Once::call_once`] except it ignores poisoning. /// This method is identical to [`Once::call_once`] except it ignores poisoning.
pub fn call_once_force(&self, f: impl FnOnce(OnceState)) { pub fn call_once_force(&self, f: impl FnOnce(OnceState)) {
let _borrow = self.id.get_borrowed(); self.id.with_held(|| self.inner.call_once_force(f));
self.inner.call_once_force(f);
} }
} }
} }

View File

@@ -30,6 +30,12 @@ pub use tracing::{
Condvar, Mutex, MutexGuard, Once, OnceLock, RwLock, RwLockReadGuard, RwLockWriteGuard, Condvar, Mutex, MutexGuard, Once, OnceLock, RwLock, RwLockReadGuard, RwLockWriteGuard,
}; };
#[cfg(all(has_std__sync__LazyLock, debug_assertions))]
pub use tracing::LazyLock;
#[cfg(all(has_std__sync__LazyLock, not(debug_assertions)))]
pub use std::sync::LazyLock;
/// Dependency tracing versions of [`std::sync`]. /// Dependency tracing versions of [`std::sync`].
pub mod tracing { pub mod tracing {
use std::fmt; use std::fmt;
@@ -47,6 +53,12 @@ pub mod tracing {
use crate::BorrowedMutex; use crate::BorrowedMutex;
use crate::LazyMutexId; use crate::LazyMutexId;
#[cfg(has_std__sync__LazyLock)]
pub use lazy_lock::LazyLock;
#[cfg(has_std__sync__LazyLock)]
mod lazy_lock;
/// Wrapper for [`std::sync::Mutex`]. /// Wrapper for [`std::sync::Mutex`].
/// ///
/// Refer to the [crate-level][`crate`] documentation for the differences between this struct and /// Refer to the [crate-level][`crate`] documentation for the differences between this struct and
@@ -161,7 +173,7 @@ pub mod tracing {
} }
} }
impl<'a, T> Deref for MutexGuard<'a, T> { impl<T> Deref for MutexGuard<'_, T> {
type Target = T; type Target = T;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
@@ -169,13 +181,13 @@ pub mod tracing {
} }
} }
impl<'a, T> DerefMut for MutexGuard<'a, T> { impl<T> DerefMut for MutexGuard<'_, T> {
fn deref_mut(&mut self) -> &mut Self::Target { fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner &mut self.inner
} }
} }
impl<'a, T: fmt::Display> fmt::Display for MutexGuard<'a, T> { impl<T: fmt::Display> fmt::Display for MutexGuard<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.inner.fmt(f) self.inner.fmt(f)
} }
@@ -409,7 +421,7 @@ pub mod tracing {
} }
} }
impl<'a, L, T> Deref for TracingRwLockGuard<'a, L> impl<L, T> Deref for TracingRwLockGuard<'_, L>
where where
L: Deref<Target = T>, L: Deref<Target = T>,
{ {
@@ -420,7 +432,7 @@ pub mod tracing {
} }
} }
impl<'a, T, L> DerefMut for TracingRwLockGuard<'a, L> impl<T, L> DerefMut for TracingRwLockGuard<'_, L>
where where
L: Deref<Target = T> + DerefMut, L: Deref<Target = T> + DerefMut,
{ {
@@ -439,6 +451,8 @@ pub mod tracing {
mutex_id: LazyMutexId, mutex_id: LazyMutexId,
} }
// New without default is intentional, `std::sync::Once` doesn't implement it either
#[allow(clippy::new_without_default)]
impl Once { impl Once {
/// Create a new `Once` value. /// Create a new `Once` value.
pub const fn new() -> Self { pub const fn new() -> Self {
@@ -458,8 +472,7 @@ pub mod tracing {
where where
F: FnOnce(), F: FnOnce(),
{ {
let _guard = self.mutex_id.get_borrowed(); self.mutex_id.with_held(|| self.inner.call_once(f))
self.inner.call_once(f);
} }
/// Performs the same operation as [`call_once`][Once::call_once] except it ignores /// Performs the same operation as [`call_once`][Once::call_once] except it ignores
@@ -473,8 +486,7 @@ pub mod tracing {
where where
F: FnOnce(&OnceState), F: FnOnce(&OnceState),
{ {
let _guard = self.mutex_id.get_borrowed(); self.mutex_id.with_held(|| self.inner.call_once_force(f))
self.inner.call_once_force(f);
} }
/// Returns true if some `call_once` has completed successfully. /// Returns true if some `call_once` has completed successfully.
@@ -548,9 +560,7 @@ pub mod tracing {
/// As this method may block until initialization is complete, it participates in cycle /// As this method may block until initialization is complete, it participates in cycle
/// detection. /// detection.
pub fn set(&self, value: T) -> Result<(), T> { pub fn set(&self, value: T) -> Result<(), T> {
let _guard = self.id.get_borrowed(); self.id.with_held(|| self.inner.set(value))
self.inner.set(value)
} }
/// Gets the contents of the cell, initializing it with `f` if the cell was empty. /// Gets the contents of the cell, initializing it with `f` if the cell was empty.
@@ -560,8 +570,7 @@ pub mod tracing {
where where
F: FnOnce() -> T, F: FnOnce() -> T,
{ {
let _guard = self.id.get_borrowed(); self.id.with_held(|| self.inner.get_or_init(f))
self.inner.get_or_init(f)
} }
/// Takes the value out of this `OnceLock`, moving it back to an uninitialized state. /// Takes the value out of this `OnceLock`, moving it back to an uninitialized state.

View File

@@ -0,0 +1,117 @@
//! Wrapper implementation for LazyLock
//!
//! This lives in a separate module as LazyLock would otherwise raise our MSRV to 1.80. Reevaluate
//! this in the future.
use std::fmt;
use std::fmt::Debug;
use std::ops::Deref;
use crate::LazyMutexId;
/// Wrapper for [`std::sync::LazyLock`]
///
/// This wrapper participates in cycle detection like all other primitives in this crate. It should
/// only be possible to encounter cycles when acquiring mutexes in the initialisation function.
///
/// # Examples
///
/// ```
/// use tracing_mutex::stdsync::tracing::LazyLock;
///
/// static LOCK: LazyLock<i32> = LazyLock::new(|| {
/// println!("Hello, world!");
/// 42
/// });
///
/// // This should print "Hello, world!"
/// println!("{}", *LOCK);
/// // This should not.
/// println!("{}", *LOCK);
/// ```
pub struct LazyLock<T, F = fn() -> T> {
// MSRV violation is fine, this is gated behind a cfg! check
#[allow(clippy::incompatible_msrv)]
inner: std::sync::LazyLock<T, F>,
id: LazyMutexId,
}
impl<T, F: FnOnce() -> T> LazyLock<T, F> {
/// Creates a new lazy value with the given initializing function.
pub const fn new(f: F) -> LazyLock<T, F> {
Self {
id: LazyMutexId::new(),
// MSRV violation is fine, this is gated behind a cfg! check
#[allow(clippy::incompatible_msrv)]
inner: std::sync::LazyLock::new(f),
}
}
/// Force this lazy lock to be evaluated.
///
/// This is equivalent to dereferencing, but is more explicit.
pub fn force(this: &LazyLock<T, F>) -> &T {
this
}
}
impl<T, F: FnOnce() -> T> Deref for LazyLock<T, F> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.id.with_held(|| &*self.inner)
}
}
impl<T: Default> Default for LazyLock<T> {
/// Return a `LazyLock` that is initialized through [`Default`].
fn default() -> Self {
Self::new(Default::default)
}
}
impl<T: Debug, F> Debug for LazyLock<T, F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// Cannot implement this ourselves because the get() used is nightly, so delegate.
self.inner.fmt(f)
}
}
#[cfg(test)]
mod tests {
use crate::stdsync::Mutex;
use super::*;
#[test]
fn test_only_init_once() {
let mut init_counter = 0;
let lock = LazyLock::new(|| {
init_counter += 1;
42
});
assert_eq!(*lock, 42);
LazyLock::force(&lock);
// Ensure we can access the init counter
drop(lock);
assert_eq!(init_counter, 1);
}
#[test]
#[should_panic(expected = "Found cycle")]
fn test_panic_with_cycle() {
let mutex = Mutex::new(());
let lock = LazyLock::new(|| *mutex.lock().unwrap());
// Establish the relation from lock to mutex
LazyLock::force(&lock);
// Now do it the other way around, which should crash
let _guard = mutex.lock().unwrap();
LazyLock::force(&lock);
}
}