Repository: rayon-rs/rayon
Pull request #1022 (2023-02-23 21:18:04)

Add TakeAny and SkipAny
The existing `take` and `skip` are only part of `IndexedParallelIterator`, while these new adaptors will take/skip from anywhere in a `ParallelIterator`.

This PR extends the documentation from #1012.


Patch:
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 23f2032..fe9b406 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -65,24 +65,16 @@ jobs:
       - run: cargo test --verbose --package rayon
       - run: cargo test --verbose --package rayon-core
 
-  # wasm32-unknown-unknown builds, and even has the runtime fallback for
-  # unsupported threading, but we don't have an environment to execute in.
-  # wasm32-wasi can test the fallback by running in wasmtime.
+  # wasm won't actually work without threading, but it builds
   wasm:
     name: WebAssembly
     runs-on: ubuntu-latest
-    env:
-      CARGO_TARGET_WASM32_WASI_RUNNER: /home/runner/.wasmtime/bin/wasmtime
     steps:
       - uses: actions/checkout@v3
       - uses: dtolnay/rust-toolchain@stable
         with:
-          targets: wasm32-unknown-unknown,wasm32-wasi
+          target: wasm32-unknown-unknown
       - run: cargo check --verbose --target wasm32-unknown-unknown
-      - run: cargo check --verbose --target wasm32-wasi
-      - run: curl https://wasmtime.dev/install.sh -sSf | bash
-      - run: cargo test --verbose --target wasm32-wasi --package rayon
-      - run: cargo test --verbose --target wasm32-wasi --package rayon-core
 
   fmt:
     name: Format
diff --git a/Cargo.toml b/Cargo.toml
index 58f1bdd..f182242 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -27,5 +27,6 @@ version = "1.0"
 default-features = false
 
 [dev-dependencies]
+lazy_static = "1"
 rand = "0.8"
 rand_xorshift = "0.3"
diff --git a/RELEASES.md b/RELEASES.md
index 498df94..f675761 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1,7 +1,3 @@
-# Release rayon-core 1.10.2 (2023-01-22)
-
-- Fixed miri-reported UB for SharedReadOnly tags protected by a call.
-
 # Release rayon 1.6.1 (2022-12-09)
 
 - Simplified `par_bridge` to only pull one item at a time from the iterator,
diff --git a/ci/compat-Cargo.lock b/ci/compat-Cargo.lock
index 1e61068..fec63f5 100644
--- a/ci/compat-Cargo.lock
+++ b/ci/compat-Cargo.lock
@@ -4,9 +4,9 @@ version = 3
 
 [[package]]
 name = "addr2line"
-version = "0.19.0"
+version = "0.17.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97"
+checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b"
 dependencies = [
  "gimli",
 ]
@@ -55,15 +55,15 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
 
 [[package]]
 name = "backtrace"
-version = "0.3.67"
+version = "0.3.66"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca"
+checksum = "cab84319d616cfb654d03394f38ab7e6f0919e181b1b57e1fd15e7fb4077d9a7"
 dependencies = [
  "addr2line",
  "cc",
  "cfg-if",
  "libc",
- "miniz_oxide",
+ "miniz_oxide 0.5.4",
  "object",
  "rustc-demangle",
 ]
@@ -82,21 +82,21 @@ checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
 
 [[package]]
 name = "bumpalo"
-version = "3.12.0"
+version = "3.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535"
+checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba"
 
 [[package]]
 name = "bytemuck"
-version = "1.13.0"
+version = "1.12.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c041d3eab048880cb0b86b256447da3f18859a163c3b8d8893f4e6368abe6393"
+checksum = "aaa3a8d9a1ca92e282c96a32d6511b695d7d994d1d102ba85d279f9b2756947f"
 
 [[package]]
 name = "calloop"
-version = "0.10.5"
+version = "0.10.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a59225be45a478d772ce015d9743e49e92798ece9e34eda9a6aa2a6a7f40192"
+checksum = "19457a0da465234abd76134a5c2a910c14bd3c5558463e4396ab9a37a328e465"
 dependencies = [
  "log",
  "nix 0.25.1",
@@ -107,9 +107,9 @@ dependencies = [
 
 [[package]]
 name = "cc"
-version = "1.0.79"
+version = "1.0.77"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
+checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4"
 
 [[package]]
 name = "cfg-if"
@@ -400,9 +400,9 @@ dependencies = [
 
 [[package]]
 name = "either"
-version = "1.8.1"
+version = "1.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
+checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
 
 [[package]]
 name = "expat-sys"
@@ -427,7 +427,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841"
 dependencies = [
  "crc32fast",
- "miniz_oxide",
+ "miniz_oxide 0.6.2",
 ]
 
 [[package]]
@@ -513,9 +513,9 @@ dependencies = [
 
 [[package]]
 name = "gimli"
-version = "0.27.2"
+version = "0.26.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4"
+checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d"
 
 [[package]]
 name = "gl_generator"
@@ -611,9 +611,9 @@ dependencies = [
 
 [[package]]
 name = "hermit-abi"
-version = "0.2.6"
+version = "0.1.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
+checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
 dependencies = [
  "libc",
 ]
@@ -644,9 +644,9 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
 
 [[package]]
 name = "js-sys"
-version = "0.3.61"
+version = "0.3.60"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730"
+checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47"
 dependencies = [
  "wasm-bindgen",
 ]
@@ -665,9 +665,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 
 [[package]]
 name = "libc"
-version = "0.2.139"
+version = "0.2.138"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
+checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
 
 [[package]]
 name = "libloading"
@@ -715,9 +715,9 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
 
 [[package]]
 name = "memmap2"
-version = "0.5.9"
+version = "0.5.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2af2c65375e552a67fe3829ca63e8a7c27a378a62824594f43b2851d682b5ec2"
+checksum = "4b182332558b18d807c4ce1ca8ca983b34c3ee32765e47b3f0f69b90355cc1dc"
 dependencies = [
  "libc",
 ]
@@ -746,6 +746,15 @@ version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
 
+[[package]]
+name = "miniz_oxide"
+version = "0.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34"
+dependencies = [
+ "adler",
+]
+
 [[package]]
 name = "miniz_oxide"
 version = "0.6.2"
@@ -757,14 +766,14 @@ dependencies = [
 
 [[package]]
 name = "mio"
-version = "0.8.6"
+version = "0.8.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9"
+checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de"
 dependencies = [
  "libc",
  "log",
  "wasi",
- "windows-sys 0.45.0",
+ "windows-sys 0.42.0",
 ]
 
 [[package]]
@@ -852,9 +861,9 @@ dependencies = [
 
 [[package]]
 name = "nom"
-version = "7.1.3"
+version = "7.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
+checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36"
 dependencies = [
  "memchr",
  "minimal-lexical",
@@ -887,9 +896,9 @@ dependencies = [
 
 [[package]]
 name = "num-complex"
-version = "0.4.3"
+version = "0.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d"
+checksum = "7ae39348c8bc5fbd7f40c727a9925f03517afd2ab27d46702108b6a7e5414c19"
 dependencies = [
  "num-traits",
 ]
@@ -938,9 +947,9 @@ dependencies = [
 
 [[package]]
 name = "num_cpus"
-version = "1.15.0"
+version = "1.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
+checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5"
 dependencies = [
  "hermit-abi",
  "libc",
@@ -948,18 +957,18 @@ dependencies = [
 
 [[package]]
 name = "num_enum"
-version = "0.5.10"
+version = "0.5.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3e0072973714303aa6e3631c7e8e777970cf4bdd25dc4932e41031027b8bcc4e"
+checksum = "cf5395665662ef45796a4ff5486c5d41d29e0c09640af4c5f17fd94ee2c119c9"
 dependencies = [
  "num_enum_derive",
 ]
 
 [[package]]
 name = "num_enum_derive"
-version = "0.5.10"
+version = "0.5.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0629cbd6b897944899b1f10496d9c4a7ac5878d45fd61bc22e9e79bfbbc29597"
+checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce"
 dependencies = [
  "proc-macro-crate",
  "proc-macro2",
@@ -978,18 +987,18 @@ dependencies = [
 
 [[package]]
 name = "object"
-version = "0.30.3"
+version = "0.29.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439"
+checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53"
 dependencies = [
  "memchr",
 ]
 
 [[package]]
 name = "once_cell"
-version = "1.17.1"
+version = "1.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
+checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
 
 [[package]]
 name = "osmesa-sys"
@@ -1012,15 +1021,15 @@ dependencies = [
 
 [[package]]
 name = "parking_lot_core"
-version = "0.9.7"
+version = "0.9.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521"
+checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba"
 dependencies = [
  "cfg-if",
  "libc",
  "redox_syscall",
  "smallvec",
- "windows-sys 0.45.0",
+ "windows-sys 0.42.0",
 ]
 
 [[package]]
@@ -1044,7 +1053,7 @@ dependencies = [
  "bitflags",
  "crc32fast",
  "flate2",
- "miniz_oxide",
+ "miniz_oxide 0.6.2",
 ]
 
 [[package]]
@@ -1066,18 +1075,18 @@ dependencies = [
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.51"
+version = "1.0.47"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6"
+checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725"
 dependencies = [
  "unicode-ident",
 ]
 
 [[package]]
 name = "quote"
-version = "1.0.23"
+version = "1.0.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
+checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
 dependencies = [
  "proc-macro2",
 ]
@@ -1144,6 +1153,7 @@ name = "rayon"
 version = "1.6.1"
 dependencies = [
  "either",
+ "lazy_static",
  "rand",
  "rand_xorshift",
  "rayon-core",
@@ -1151,7 +1161,7 @@ dependencies = [
 
 [[package]]
 name = "rayon-core"
-version = "1.10.2"
+version = "1.10.1"
 dependencies = [
  "crossbeam-channel",
  "crossbeam-deque",
@@ -1172,9 +1182,9 @@ dependencies = [
  "docopt",
  "fixedbitset",
  "glium",
+ "lazy_static",
  "libc",
  "num",
- "once_cell",
  "rand",
  "rand_xorshift",
  "rayon",
@@ -1194,9 +1204,9 @@ dependencies = [
 
 [[package]]
 name = "regex"
-version = "1.7.1"
+version = "1.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733"
+checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -1250,18 +1260,18 @@ dependencies = [
 
 [[package]]
 name = "serde"
-version = "1.0.152"
+version = "1.0.149"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
+checksum = "256b9932320c590e707b94576e3cc1f7c9024d0ee6612dfbcf1cb106cbe8e055"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.152"
+version = "1.0.149"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
+checksum = "b4eae9b04cbffdfd550eb462ed33bc6a1b68c935127d008b27444d08380f94e4"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1341,9 +1351,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
 
 [[package]]
 name = "syn"
-version = "1.0.107"
+version = "1.0.105"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
+checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1358,18 +1368,18 @@ checksum = "36ae8932fcfea38b7d3883ae2ab357b0d57a02caaa18ebb4f5ece08beaec4aa0"
 
 [[package]]
 name = "thiserror"
-version = "1.0.38"
+version = "1.0.37"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
+checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.38"
+version = "1.0.37"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
+checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1403,18 +1413,18 @@ dependencies = [
 
 [[package]]
 name = "toml"
-version = "0.5.11"
+version = "0.5.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
+checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7"
 dependencies = [
  "serde",
 ]
 
 [[package]]
 name = "unicode-ident"
-version = "1.0.6"
+version = "1.0.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
+checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
 
 [[package]]
 name = "vec_map"
@@ -1436,9 +1446,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
 name = "wasm-bindgen"
-version = "0.2.84"
+version = "0.2.83"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b"
+checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268"
 dependencies = [
  "cfg-if",
  "wasm-bindgen-macro",
@@ -1446,9 +1456,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-backend"
-version = "0.2.84"
+version = "0.2.83"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9"
+checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142"
 dependencies = [
  "bumpalo",
  "log",
@@ -1461,9 +1471,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro"
-version = "0.2.84"
+version = "0.2.83"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5"
+checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810"
 dependencies = [
  "quote",
  "wasm-bindgen-macro-support",
@@ -1471,9 +1481,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro-support"
-version = "0.2.84"
+version = "0.2.83"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6"
+checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1484,9 +1494,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-shared"
-version = "0.2.84"
+version = "0.2.83"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d"
+checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f"
 
 [[package]]
 name = "wayland-client"
@@ -1573,9 +1583,9 @@ dependencies = [
 
 [[package]]
 name = "web-sys"
-version = "0.3.61"
+version = "0.3.60"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97"
+checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f"
 dependencies = [
  "js-sys",
  "wasm-bindgen",
@@ -1618,33 +1628,24 @@ dependencies = [
 
 [[package]]
 name = "windows-sys"
-version = "0.45.0"
+version = "0.42.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
-dependencies = [
- "windows-targets",
-]
-
-[[package]]
-name = "windows-targets"
-version = "0.42.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7"
+checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
 dependencies = [
  "windows_aarch64_gnullvm",
- "windows_aarch64_msvc 0.42.1",
- "windows_i686_gnu 0.42.1",
- "windows_i686_msvc 0.42.1",
- "windows_x86_64_gnu 0.42.1",
+ "windows_aarch64_msvc 0.42.0",
+ "windows_i686_gnu 0.42.0",
+ "windows_i686_msvc 0.42.0",
+ "windows_x86_64_gnu 0.42.0",
  "windows_x86_64_gnullvm",
- "windows_x86_64_msvc 0.42.1",
+ "windows_x86_64_msvc 0.42.0",
 ]
 
 [[package]]
 name = "windows_aarch64_gnullvm"
-version = "0.42.1"
+version = "0.42.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
+checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
 
 [[package]]
 name = "windows_aarch64_msvc"
@@ -1654,9 +1655,9 @@ checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
 
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.42.1"
+version = "0.42.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
+checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
 
 [[package]]
 name = "windows_i686_gnu"
@@ -1666,9 +1667,9 @@ checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.42.1"
+version = "0.42.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
+checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
 
 [[package]]
 name = "windows_i686_msvc"
@@ -1678,9 +1679,9 @@ checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.42.1"
+version = "0.42.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
+checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
 
 [[package]]
 name = "windows_x86_64_gnu"
@@ -1690,15 +1691,15 @@ checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.42.1"
+version = "0.42.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
+checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
-version = "0.42.1"
+version = "0.42.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
+checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
 
 [[package]]
 name = "windows_x86_64_msvc"
@@ -1708,9 +1709,9 @@ checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.42.1"
+version = "0.42.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
+checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
 
 [[package]]
 name = "winit"
@@ -1756,12 +1757,12 @@ dependencies = [
 
 [[package]]
 name = "x11-dl"
-version = "2.21.0"
+version = "2.20.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f"
+checksum = "b1536d6965a5d4e573c7ef73a2c15ebcd0b2de3347bdf526c34c297c00ac40f0"
 dependencies = [
+ "lazy_static",
  "libc",
- "once_cell",
  "pkg-config",
 ]
 
diff --git a/rayon-core/Cargo.toml b/rayon-core/Cargo.toml
index 878dac7..3b0ed14 100644
--- a/rayon-core/Cargo.toml
+++ b/rayon-core/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "rayon-core"
-version = "1.10.2"
+version = "1.10.1"
 authors = ["Niko Matsakis <niko@alum.mit.edu>",
            "Josh Stone <cuviper@gmail.com>"]
 description = "Core APIs for Rayon"
diff --git a/rayon-core/src/broadcast/mod.rs b/rayon-core/src/broadcast/mod.rs
index d991c54..452aa71 100644
--- a/rayon-core/src/broadcast/mod.rs
+++ b/rayon-core/src/broadcast/mod.rs
@@ -1,5 +1,4 @@
 use crate::job::{ArcJob, StackJob};
-use crate::latch::LatchRef;
 use crate::registry::{Registry, WorkerThread};
 use crate::scope::ScopeLatch;
 use std::fmt;
@@ -108,9 +107,7 @@ where
     let n_threads = registry.num_threads();
     let current_thread = WorkerThread::current().as_ref();
     let latch = ScopeLatch::with_count(n_threads, current_thread);
-    let jobs: Vec<_> = (0..n_threads)
-        .map(|_| StackJob::new(&f, LatchRef::new(&latch)))
-        .collect();
+    let jobs: Vec<_> = (0..n_threads).map(|_| StackJob::new(&f, &latch)).collect();
     let job_refs = jobs.iter().map(|job| job.as_job_ref());
 
     registry.inject_broadcast(job_refs);
diff --git a/rayon-core/src/job.rs b/rayon-core/src/job.rs
index deccebc..b7a3dae 100644
--- a/rayon-core/src/job.rs
+++ b/rayon-core/src/job.rs
@@ -112,7 +112,7 @@ where
         let abort = unwind::AbortIfPanic;
         let func = (*this.func.get()).take().unwrap();
         (*this.result.get()) = JobResult::call(func);
-        Latch::set(&this.latch);
+        this.latch.set();
         mem::forget(abort);
     }
 }
diff --git a/rayon-core/src/latch.rs b/rayon-core/src/latch.rs
index de43272..0909293 100644
--- a/rayon-core/src/latch.rs
+++ b/rayon-core/src/latch.rs
@@ -1,5 +1,3 @@
-use std::marker::PhantomData;
-use std::ops::Deref;
 use std::sync::atomic::{AtomicUsize, Ordering};
 use std::sync::{Arc, Condvar, Mutex};
 use std::usize;
@@ -39,15 +37,10 @@ pub(super) trait Latch {
     ///
     /// Setting a latch triggers other threads to wake up and (in some
     /// cases) complete. This may, in turn, cause memory to be
-    /// deallocated and so forth. One must be very careful about this,
+    /// allocated and so forth.  One must be very careful about this,
     /// and it's typically better to read all the fields you will need
     /// to access *before* a latch is set!
-    ///
-    /// This function operates on `*const Self` instead of `&self` to allow it
-    /// to become dangling during this call. The caller must ensure that the
-    /// pointer is valid upon entry, and not invalidated during the call by any
-    /// actions other than `set` itself.
-    unsafe fn set(this: *const Self);
+    fn set(&self);
 }
 
 pub(super) trait AsCoreLatch {
@@ -130,8 +123,8 @@ impl CoreLatch {
     /// doing some wakeups; those are encapsulated in the surrounding
     /// latch code.
     #[inline]
-    unsafe fn set(this: *const Self) -> bool {
-        let old_state = (*this).state.swap(SET, Ordering::AcqRel);
+    fn set(&self) -> bool {
+        let old_state = self.state.swap(SET, Ordering::AcqRel);
         old_state == SLEEPING
     }
 
@@ -193,16 +186,16 @@ impl<'r> AsCoreLatch for SpinLatch<'r> {
 
 impl<'r> Latch for SpinLatch<'r> {
     #[inline]
-    unsafe fn set(this: *const Self) {
+    fn set(&self) {
         let cross_registry;
 
-        let registry: &Registry = if (*this).cross {
+        let registry: &Registry = if self.cross {
             // Ensure the registry stays alive while we notify it.
             // Otherwise, it would be possible that we set the spin
             // latch and the other thread sees it and exits, causing
             // the registry to be deallocated, all before we get a
             // chance to invoke `registry.notify_worker_latch_is_set`.
-            cross_registry = Arc::clone((*this).registry);
+            cross_registry = Arc::clone(self.registry);
             &cross_registry
         } else {
             // If this is not a "cross-registry" spin-latch, then the
@@ -210,12 +203,12 @@ impl<'r> Latch for SpinLatch<'r> {
             // that the registry stays alive. However, that doesn't
             // include this *particular* `Arc` handle if the waiting
             // thread then exits, so we must completely dereference it.
-            (*this).registry
+            self.registry
         };
-        let target_worker_index = (*this).target_worker_index;
+        let target_worker_index = self.target_worker_index;
 
-        // NOTE: Once we `set`, the target may proceed and invalidate `this`!
-        if CoreLatch::set(&(*this).core_latch) {
+        // NOTE: Once we `set`, the target may proceed and invalidate `&self`!
+        if self.core_latch.set() {
             // Subtle: at this point, we can no longer read from
             // `self`, because the thread owning this spin latch may
             // have awoken and deallocated the latch. Therefore, we
@@ -262,10 +255,10 @@ impl LockLatch {
 
 impl Latch for LockLatch {
     #[inline]
-    unsafe fn set(this: *const Self) {
-        let mut guard = (*this).m.lock().unwrap();
+    fn set(&self) {
+        let mut guard = self.m.lock().unwrap();
         *guard = true;
-        (*this).v.notify_all();
+        self.v.notify_all();
     }
 }
 
@@ -314,9 +307,9 @@ impl CountLatch {
     /// count, then the latch is **set**, and calls to `probe()` will
     /// return true. Returns whether the latch was set.
     #[inline]
-    pub(super) unsafe fn set(this: *const Self) -> bool {
-        if (*this).counter.fetch_sub(1, Ordering::SeqCst) == 1 {
-            CoreLatch::set(&(*this).core_latch);
+    pub(super) fn set(&self) -> bool {
+        if self.counter.fetch_sub(1, Ordering::SeqCst) == 1 {
+            self.core_latch.set();
             true
         } else {
             false
@@ -327,12 +320,8 @@ impl CountLatch {
     /// the latch is set, then the specific worker thread is tickled,
     /// which should be the one that owns this latch.
     #[inline]
-    pub(super) unsafe fn set_and_tickle_one(
-        this: *const Self,
-        registry: &Registry,
-        target_worker_index: usize,
-    ) {
-        if Self::set(this) {
+    pub(super) fn set_and_tickle_one(&self, registry: &Registry, target_worker_index: usize) {
+        if self.set() {
             registry.notify_worker_latch_is_set(target_worker_index);
         }
     }
@@ -373,42 +362,19 @@ impl CountLockLatch {
 
 impl Latch for CountLockLatch {
     #[inline]
-    unsafe fn set(this: *const Self) {
-        if (*this).counter.fetch_sub(1, Ordering::SeqCst) == 1 {
-            LockLatch::set(&(*this).lock_latch);
+    fn set(&self) {
+        if self.counter.fetch_sub(1, Ordering::SeqCst) == 1 {
+            self.lock_latch.set();
         }
     }
 }
 
-/// `&L` without any implication of `dereferenceable` for `Latch::set`
-pub(super) struct LatchRef<'a, L> {
-    inner: *const L,
-    marker: PhantomData<&'a L>,
-}
-
-impl<L> LatchRef<'_, L> {
-    pub(super) fn new(inner: &L) -> LatchRef<'_, L> {
-        LatchRef {
-            inner,
-            marker: PhantomData,
-        }
-    }
-}
-
-unsafe impl<L: Sync> Sync for LatchRef<'_, L> {}
-
-impl<L> Deref for LatchRef<'_, L> {
-    type Target = L;
-
-    fn deref(&self) -> &L {
-        // SAFETY: if we have &self, the inner latch is still alive
-        unsafe { &*self.inner }
-    }
-}
-
-impl<L: Latch> Latch for LatchRef<'_, L> {
+impl<'a, L> Latch for &'a L
+where
+    L: Latch,
+{
     #[inline]
-    unsafe fn set(this: *const Self) {
-        L::set((*this).inner);
+    fn set(&self) {
+        L::set(self);
     }
 }
diff --git a/rayon-core/src/lib.rs b/rayon-core/src/lib.rs
index 8ef4d6b..b31a2d7 100644
--- a/rayon-core/src/lib.rs
+++ b/rayon-core/src/lib.rs
@@ -26,23 +26,7 @@
 //! [`join()`]: struct.ThreadPool.html#method.join
 //! [`ThreadPoolBuilder`]: struct.ThreadPoolBuilder.html
 //!
-//! # Global fallback when threading is unsupported
-//!
-//! Rayon uses `std` APIs for threading, but some targets have incomplete implementations that
-//! always return `Unsupported` errors. The WebAssembly `wasm32-unknown-unknown` and `wasm32-wasi`
-//! targets are notable examples of this. Rather than panicking on the unsupported error when
-//! creating the implicit global threadpool, Rayon configures a fallback mode instead.
-//!
-//! This fallback mode mostly functions as if it were using a single-threaded "pool", like setting
-//! `RAYON_NUM_THREADS=1`. For example, `join` will execute its two closures sequentially, since
-//! there is no other thread to share the work. However, since the pool is not running independent
-//! of the main thread, non-blocking calls like `spawn` may not execute at all, unless a lower-
-//! priority call like `broadcast` gives them an opening. The fallback mode does not try to emulate
-//! anything like thread preemption or `async` task switching.
-//!
-//! Explicit `ThreadPoolBuilder` methods always report their error without any fallback.
-//!
-//! # Restricting multiple versions
+//! ## Restricting multiple versions
 //!
 //! In order to ensure proper coordination between threadpools, and especially
 //! to make sure there's only one global threadpool, `rayon-core` is actively
@@ -723,10 +707,6 @@ impl ThreadPoolBuildError {
     fn new(kind: ErrorKind) -> ThreadPoolBuildError {
         ThreadPoolBuildError { kind }
     }
-
-    fn is_unsupported(&self) -> bool {
-        matches!(&self.kind, ErrorKind::IOError(e) if e.kind() == io::ErrorKind::Unsupported)
-    }
 }
 
 const GLOBAL_POOL_ALREADY_INITIALIZED: &str =
diff --git a/rayon-core/src/registry.rs b/rayon-core/src/registry.rs
index cd02123..279e298 100644
--- a/rayon-core/src/registry.rs
+++ b/rayon-core/src/registry.rs
@@ -1,5 +1,5 @@
 use crate::job::{JobFifo, JobRef, StackJob};
-use crate::latch::{AsCoreLatch, CoreLatch, CountLatch, Latch, LatchRef, LockLatch, SpinLatch};
+use crate::latch::{AsCoreLatch, CoreLatch, CountLatch, Latch, LockLatch, SpinLatch};
 use crate::log::Event::*;
 use crate::log::Logger;
 use crate::sleep::Sleep;
@@ -50,7 +50,7 @@ impl ThreadBuilder {
     /// Executes the main loop for this thread. This will not return until the
     /// thread pool is dropped.
     pub fn run(self) {
-        unsafe { main_loop(self) }
+        unsafe { main_loop(self.worker, self.stealer, self.registry, self.index) }
     }
 }
 
@@ -164,7 +164,7 @@ static THE_REGISTRY_SET: Once = Once::new();
 /// initialization has not already occurred, use the default
 /// configuration.
 pub(super) fn global_registry() -> &'static Arc<Registry> {
-    set_global_registry(default_global_registry)
+    set_global_registry(|| Registry::new(ThreadPoolBuilder::new()))
         .or_else(|err| unsafe { THE_REGISTRY.as_ref().ok_or(err) })
         .expect("The global thread pool has not been initialized.")
 }
@@ -198,46 +198,6 @@ where
     result
 }
 
-fn default_global_registry() -> Result<Arc<Registry>, ThreadPoolBuildError> {
-    let result = Registry::new(ThreadPoolBuilder::new());
-
-    // If we're running in an environment that doesn't support threads at all, we can fall back to
-    // using the current thread alone. This is crude, and probably won't work for non-blocking
-    // calls like `spawn` or `broadcast_spawn`, but a lot of stuff does work fine.
-    //
-    // Notably, this allows current WebAssembly targets to work even though their threading support
-    // is stubbed out, and we won't have to change anything if they do add real threading.
-    let unsupported = matches!(&result, Err(e) if e.is_unsupported());
-    if unsupported && WorkerThread::current().is_null() {
-        let builder = ThreadPoolBuilder::new()
-            .num_threads(1)
-            .spawn_handler(|thread| {
-                // Rather than starting a new thread, we're just taking over the current thread
-                // *without* running the main loop, so we can still return from here.
-                // The WorkerThread is leaked, but we never shutdown the global pool anyway.
-                let worker_thread = Box::leak(Box::new(WorkerThread::from(thread)));
-                let registry = &*worker_thread.registry;
-                let index = worker_thread.index;
-
-                unsafe {
-                    WorkerThread::set_current(worker_thread);
-
-                    // let registry know we are ready to do work
-                    Latch::set(&registry.thread_infos[index].primed);
-                }
-
-                Ok(())
-            });
-
-        let fallback_result = Registry::new(builder);
-        if fallback_result.is_ok() {
-            return fallback_result;
-        }
-    }
-
-    result
-}
-
 struct Terminator<'a>(&'a Arc<Registry>);
 
 impl<'a> Drop for Terminator<'a> {
@@ -545,7 +505,7 @@ impl Registry {
                     assert!(injected && !worker_thread.is_null());
                     op(&*worker_thread, true)
                 },
-                LatchRef::new(l),
+                l,
             );
             self.inject(&[job.as_job_ref()]);
             job.latch.wait_and_reset(); // Make sure we can use the same latch again next time.
@@ -615,7 +575,7 @@ impl Registry {
     pub(super) fn terminate(&self) {
         if self.terminate_count.fetch_sub(1, Ordering::AcqRel) == 1 {
             for (i, thread_info) in self.thread_infos.iter().enumerate() {
-                unsafe { CountLatch::set_and_tickle_one(&thread_info.terminate, self, i) };
+                thread_info.terminate.set_and_tickle_one(self, i);
             }
         }
     }
@@ -695,19 +655,6 @@ thread_local! {
     static WORKER_THREAD_STATE: Cell<*const WorkerThread> = Cell::new(ptr::null());
 }
 
-impl From<ThreadBuilder> for WorkerThread {
-    fn from(thread: ThreadBuilder) -> Self {
-        Self {
-            worker: thread.worker,
-            stealer: thread.stealer,
-            fifo: JobFifo::new(),
-            index: thread.index,
-            rng: XorShift64Star::new(),
-            registry: thread.registry,
-        }
-    }
-}
-
 impl Drop for WorkerThread {
     fn drop(&mut self) {
         // Undo `set_current`
@@ -904,14 +851,25 @@ impl WorkerThread {
 
 /// ////////////////////////////////////////////////////////////////////////
 
-unsafe fn main_loop(thread: ThreadBuilder) {
-    let worker_thread = &WorkerThread::from(thread);
+unsafe fn main_loop(
+    worker: Worker<JobRef>,
+    stealer: Stealer<JobRef>,
+    registry: Arc<Registry>,
+    index: usize,
+) {
+    let worker_thread = &WorkerThread {
+        worker,
+        stealer,
+        fifo: JobFifo::new(),
+        index,
+        rng: XorShift64Star::new(),
+        registry,
+    };
     WorkerThread::set_current(worker_thread);
     let registry = &*worker_thread.registry;
-    let index = worker_thread.index;
 
     // let registry know we are ready to do work
-    Latch::set(&registry.thread_infos[index].primed);
+    registry.thread_infos[index].primed.set();
 
     // Worker threads should not panic. If they do, just abort, as the
     // internal state of the threadpool is corrupted. Note that if
@@ -934,7 +892,7 @@ unsafe fn main_loop(thread: ThreadBuilder) {
     debug_assert!(worker_thread.take_local_job().is_none());
 
     // let registry know we are done
-    Latch::set(&registry.thread_infos[index].stopped);
+    registry.thread_infos[index].stopped.set();
 
     // Normal termination, do not abort.
     mem::forget(abort_guard);
@@ -966,7 +924,7 @@ where
             // invalidated until we return.
             op(&*owner_thread, false)
         } else {
-            global_registry().in_worker(op)
+            global_registry().in_worker_cold(op)
         }
     }
 }
diff --git a/rayon-core/src/scope/mod.rs b/rayon-core/src/scope/mod.rs
index b014cf0..be3e7c3 100644
--- a/rayon-core/src/scope/mod.rs
+++ b/rayon-core/src/scope/mod.rs
@@ -540,10 +540,10 @@ impl<'scope> Scope<'scope> {
         BODY: FnOnce(&Scope<'scope>) + Send + 'scope,
     {
         let scope_ptr = ScopePtr(self);
-        let job = HeapJob::new(move || unsafe {
+        let job = HeapJob::new(move || {
             // SAFETY: this job will execute before the scope ends.
-            let scope = scope_ptr.as_ref();
-            ScopeBase::execute_job(&scope.base, move || body(scope))
+            let scope = unsafe { scope_ptr.as_ref() };
+            scope.base.execute_job(move || body(scope))
         });
         let job_ref = self.base.heap_job_ref(job);
 
@@ -562,12 +562,12 @@ impl<'scope> Scope<'scope> {
         BODY: Fn(&Scope<'scope>, BroadcastContext<'_>) + Send + Sync + 'scope,
     {
         let scope_ptr = ScopePtr(self);
-        let job = ArcJob::new(move || unsafe {
+        let job = ArcJob::new(move || {
             // SAFETY: this job will execute before the scope ends.
-            let scope = scope_ptr.as_ref();
+            let scope = unsafe { scope_ptr.as_ref() };
             let body = &body;
             let func = move || BroadcastContext::with(move |ctx| body(scope, ctx));
-            ScopeBase::execute_job(&scope.base, func)
+            scope.base.execute_job(func);
         });
         self.base.inject_broadcast(job)
     }
@@ -600,10 +600,10 @@ impl<'scope> ScopeFifo<'scope> {
         BODY: FnOnce(&ScopeFifo<'scope>) + Send + 'scope,
     {
         let scope_ptr = ScopePtr(self);
-        let job = HeapJob::new(move || unsafe {
+        let job = HeapJob::new(move || {
             // SAFETY: this job will execute before the scope ends.
-            let scope = scope_ptr.as_ref();
-            ScopeBase::execute_job(&scope.base, move || body(scope))
+            let scope = unsafe { scope_ptr.as_ref() };
+            scope.base.execute_job(move || body(scope))
         });
         let job_ref = self.base.heap_job_ref(job);
 
@@ -628,12 +628,12 @@ impl<'scope> ScopeFifo<'scope> {
         BODY: Fn(&ScopeFifo<'scope>, BroadcastContext<'_>) + Send + Sync + 'scope,
     {
         let scope_ptr = ScopePtr(self);
-        let job = ArcJob::new(move || unsafe {
+        let job = ArcJob::new(move || {
             // SAFETY: this job will execute before the scope ends.
-            let scope = scope_ptr.as_ref();
+            let scope = unsafe { scope_ptr.as_ref() };
             let body = &body;
             let func = move || BroadcastContext::with(move |ctx| body(scope, ctx));
-            ScopeBase::execute_job(&scope.base, func)
+            scope.base.execute_job(func);
         });
         self.base.inject_broadcast(job)
     }
@@ -688,7 +688,7 @@ impl<'scope> ScopeBase<'scope> {
     where
         FUNC: FnOnce() -> R,
     {
-        let result = unsafe { Self::execute_job_closure(self, func) };
+        let result = self.execute_job_closure(func);
         self.job_completed_latch.wait(owner);
         self.maybe_propagate_panic();
         result.unwrap() // only None if `op` panicked, and that would have been propagated
@@ -696,28 +696,28 @@ impl<'scope> ScopeBase<'scope> {
 
     /// Executes `func` as a job, either aborting or executing as
     /// appropriate.
-    unsafe fn execute_job<FUNC>(this: *const Self, func: FUNC)
+    fn execute_job<FUNC>(&self, func: FUNC)
     where
         FUNC: FnOnce(),
     {
-        let _: Option<()> = Self::execute_job_closure(this, func);
+        let _: Option<()> = self.execute_job_closure(func);
     }
 
     /// Executes `func` as a job in scope. Adjusts the "job completed"
     /// counters and also catches any panic and stores it into
     /// `scope`.
-    unsafe fn execute_job_closure<FUNC, R>(this: *const Self, func: FUNC) -> Option<R>
+    fn execute_job_closure<FUNC, R>(&self, func: FUNC) -> Option<R>
     where
         FUNC: FnOnce() -> R,
     {
         match unwind::halt_unwinding(func) {
             Ok(r) => {
-                Latch::set(&(*this).job_completed_latch);
+                self.job_completed_latch.set();
                 Some(r)
             }
             Err(err) => {
-                (*this).job_panicked(err);
-                Latch::set(&(*this).job_completed_latch);
+                self.job_panicked(err);
+                self.job_completed_latch.set();
                 None
             }
         }
@@ -797,14 +797,14 @@ impl ScopeLatch {
 }
 
 impl Latch for ScopeLatch {
-    unsafe fn set(this: *const Self) {
-        match &*this {
+    fn set(&self) {
+        match self {
             ScopeLatch::Stealing {
                 latch,
                 registry,
                 worker_index,
-            } => CountLatch::set_and_tickle_one(latch, registry, *worker_index),
-            ScopeLatch::Blocking { latch } => Latch::set(latch),
+            } => latch.set_and_tickle_one(registry, *worker_index),
+            ScopeLatch::Blocking { latch } => latch.set(),
         }
     }
 }
diff --git a/rayon-demo/Cargo.toml b/rayon-demo/Cargo.toml
index 11a595b..d13ea47 100644
--- a/rayon-demo/Cargo.toml
+++ b/rayon-demo/Cargo.toml
@@ -12,7 +12,7 @@ cgmath = "0.18"
 docopt = "1"
 fixedbitset = "0.4"
 glium = "0.32"
-once_cell = "1.17.1"
+lazy_static = "1"
 rand = "0.8"
 rand_xorshift = "0.3"
 regex = "1"
diff --git a/rayon-demo/src/find/mod.rs b/rayon-demo/src/find/mod.rs
index 12e257f..1094017 100644
--- a/rayon-demo/src/find/mod.rs
+++ b/rayon-demo/src/find/mod.rs
@@ -3,23 +3,24 @@
 macro_rules! make_tests {
     ($n:expr, $m:ident) => {
         mod $m {
-            use once_cell::sync::Lazy;
             use rand::distributions::Standard;
             use rand::Rng;
             use rayon::prelude::*;
             use test::Bencher;
 
-            static HAYSTACK: Lazy<Box<[[u32; $n]]>> = Lazy::new(|| {
-                let rng = crate::seeded_rng();
-                rng.sample_iter(&Standard)
-                    .map(|x| {
-                        let mut result: [u32; $n] = [0; $n];
-                        result[0] = x;
-                        result
-                    })
-                    .take(10_000_000)
-                    .collect()
-            });
+            lazy_static::lazy_static! {
+                static ref HAYSTACK: Vec<[u32; $n]> = {
+                    let rng = crate::seeded_rng();
+                    rng.sample_iter(&Standard)
+                        .map(|x| {
+                            let mut result: [u32; $n] = [0; $n];
+                            result[0] = x;
+                            result
+                        })
+                        .take(10_000_000)
+                        .collect()
+                };
+            }
 
             #[bench]
             fn parallel_find_first(b: &mut Bencher) {
diff --git a/rayon-demo/src/str_split.rs b/rayon-demo/src/str_split.rs
index c55ecab..7bcfc89 100644
--- a/rayon-demo/src/str_split.rs
+++ b/rayon-demo/src/str_split.rs
@@ -1,18 +1,18 @@
 //! Some microbenchmarks for splitting strings
 
-use once_cell::sync::Lazy;
 use rand::seq::SliceRandom;
 use rayon::prelude::*;
 use test::Bencher;
 
-static HAYSTACK: Lazy<String> = Lazy::new(|| {
-    let mut rng = crate::seeded_rng();
-    let mut bytes: Vec<u8> = "abcdefg ".bytes().cycle().take(1_000_000).collect();
-    bytes.shuffle(&mut rng);
-    String::from_utf8(bytes).unwrap()
-});
-
-static COUNT: Lazy<usize> = Lazy::new(|| HAYSTACK.split(' ').count());
+lazy_static::lazy_static! {
+    static ref HAYSTACK: String = {
+        let mut rng = crate::seeded_rng();
+        let mut bytes: Vec<u8> = "abcdefg ".bytes().cycle().take(1_000_000).collect();
+        bytes.shuffle(&mut rng);
+        String::from_utf8(bytes).unwrap()
+    };
+    static ref COUNT: usize = HAYSTACK.split(' ').count();
+}
 
 // Try multiple kinds of whitespace, but HAYSTACK only contains plain spaces.
 const WHITESPACE: &[char] = &['\r', '\n', ' ', '\t'];
diff --git a/rayon-demo/src/tsp/parser.rs b/rayon-demo/src/tsp/parser.rs
index 1d8f40f..6931281 100644
--- a/rayon-demo/src/tsp/parser.rs
+++ b/rayon-demo/src/tsp/parser.rs
@@ -1,4 +1,3 @@
-use once_cell::sync::Lazy;
 use regex::Regex;
 use std::collections::HashMap;
 use std::str::{FromStr, Lines};
@@ -24,9 +23,13 @@ use super::weight::Weight;
 // NODE_COORD_SECTION
 // 1 11003.611100 42102.500000
 
-static HEADER: Lazy<Regex> = Lazy::new(|| Regex::new(r"([A-Z_]+)\s*:(.*)").unwrap());
+lazy_static::lazy_static! {
+    static ref HEADER: Regex = Regex::new(r"([A-Z_]+)\s*:(.*)").unwrap();
+}
 
-static COORD: Lazy<Regex> = Lazy::new(|| Regex::new(r"([0-9]+) ([0-9.]+) ([0-9.]+)").unwrap());
+lazy_static::lazy_static! {
+    static ref COORD: Regex = Regex::new(r"([0-9]+) ([0-9.]+) ([0-9.]+)").unwrap();
+}
 
 pub fn parse_tsp_data(text: &str) -> Result<Graph, String> {
     let mut data = Data::new(text);
diff --git a/src/iter/mod.rs b/src/iter/mod.rs
index 98c9326..b8e6841 100644
--- a/src/iter/mod.rs
+++ b/src/iter/mod.rs
@@ -141,10 +141,12 @@ mod reduce;
 mod repeat;
 mod rev;
 mod skip;
+mod skip_any;
 mod splitter;
 mod step_by;
 mod sum;
 mod take;
+mod take_any;
 mod try_fold;
 mod try_reduce;
 mod try_reduce_with;
@@ -185,9 +187,11 @@ pub use self::{
     repeat::{repeat, repeatn, Repeat, RepeatN},
     rev::Rev,
     skip::Skip,
+    skip_any::SkipAny,
     splitter::{split, Split},
     step_by::StepBy,
     take::Take,
+    take_any::TakeAny,
     try_fold::{TryFold, TryFoldWith},
     update::Update,
     while_some::WhileSome,
@@ -2194,6 +2198,56 @@ pub trait ParallelIterator: Sized + Send {
         Intersperse::new(self, element)
     }
 
+    /// Creates an iterator that yields `n` elements from *anywhere* in the original iterator.
+    ///
+    /// This is similar to [`IndexedParallelIterator::take`] without being
+    /// constrained to the "first" `n` of the original iterator order. The
+    /// taken items will still maintain their relative order where that is
+    /// visible in `collect`, `reduce`, and similar outputs.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use rayon::prelude::*;
+    ///
+    /// let result: Vec<_> = (0..100)
+    ///     .into_par_iter()
+    ///     .filter(|&x| x % 2 == 0)
+    ///     .take_any(5)
+    ///     .collect();
+    ///
+    /// assert_eq!(result.len(), 5);
+    /// assert!(result.windows(2).all(|w| w[0] < w[1]));
+    /// ```
+    fn take_any(self, n: usize) -> TakeAny<Self> {
+        TakeAny::new(self, n)
+    }
+
+    /// Creates an iterator that skips `n` elements from *anywhere* in the original iterator.
+    ///
+    /// This is similar to [`IndexedParallelIterator::skip`] without being
+    /// constrained to the "first" `n` of the original iterator order. The
+    /// remaining items will still maintain their relative order where that is
+    /// visible in `collect`, `reduce`, and similar outputs.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use rayon::prelude::*;
+    ///
+    /// let result: Vec<_> = (0..100)
+    ///     .into_par_iter()
+    ///     .filter(|&x| x % 2 == 0)
+    ///     .skip_any(5)
+    ///     .collect();
+    ///
+    /// assert_eq!(result.len(), 45);
+    /// assert!(result.windows(2).all(|w| w[0] < w[1]));
+    /// ```
+    fn skip_any(self, n: usize) -> SkipAny<Self> {
+        SkipAny::new(self, n)
+    }
+
     /// Internal method used to define the behavior of this parallel
     /// iterator. You should not need to call this directly.
     ///
diff --git a/src/iter/skip_any.rs b/src/iter/skip_any.rs
new file mode 100644
index 0000000..2ce0a75
--- /dev/null
+++ b/src/iter/skip_any.rs
@@ -0,0 +1,148 @@
+use super::plumbing::*;
+use super::*;
+use std::sync::atomic::{AtomicUsize, Ordering};
+
+/// `SkipAny` is an iterator that skips over `n` elements from anywhere in `I`.
+/// This struct is created by the [`skip_any()`] method on [`ParallelIterator`]
+///
+/// [`skip_any()`]: trait.ParallelIterator.html#method.skip_any
+/// [`ParallelIterator`]: trait.ParallelIterator.html
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[derive(Debug)]
+pub struct SkipAny<I: ParallelIterator> {
+    base: I,
+    count: AtomicUsize,
+}
+
+impl<I> SkipAny<I>
+where
+    I: ParallelIterator,
+{
+    /// Creates a new `SkipAny` iterator.
+    pub(super) fn new(base: I, count: usize) -> Self {
+        SkipAny {
+            base,
+            count: AtomicUsize::new(count),
+        }
+    }
+}
+
+impl<I, T> ParallelIterator for SkipAny<I>
+where
+    I: ParallelIterator<Item = T>,
+    T: Send,
+{
+    type Item = T;
+
+    fn drive_unindexed<C>(self, consumer: C) -> C::Result
+    where
+        C: UnindexedConsumer<Self::Item>,
+    {
+        let consumer1 = SkipAnyConsumer {
+            base: consumer,
+            count: &self.count,
+        };
+        self.base.drive_unindexed(consumer1)
+    }
+}
+
+/// ////////////////////////////////////////////////////////////////////////
+/// Consumer implementation
+
+struct SkipAnyConsumer<'f, C> {
+    base: C,
+    count: &'f AtomicUsize,
+}
+
+impl<'f, T, C> Consumer<T> for SkipAnyConsumer<'f, C>
+where
+    C: Consumer<T>,
+    T: Send,
+{
+    type Folder = SkipAnyFolder<'f, C::Folder>;
+    type Reducer = C::Reducer;
+    type Result = C::Result;
+
+    fn split_at(self, index: usize) -> (Self, Self, Self::Reducer) {
+        let (left, right, reducer) = self.base.split_at(index);
+        (
+            SkipAnyConsumer { base: left, ..self },
+            SkipAnyConsumer {
+                base: right,
+                ..self
+            },
+            reducer,
+        )
+    }
+
+    fn into_folder(self) -> Self::Folder {
+        SkipAnyFolder {
+            base: self.base.into_folder(),
+            count: self.count,
+        }
+    }
+
+    fn full(&self) -> bool {
+        self.base.full()
+    }
+}
+
+impl<'f, T, C> UnindexedConsumer<T> for SkipAnyConsumer<'f, C>
+where
+    C: UnindexedConsumer<T>,
+    T: Send,
+{
+    fn split_off_left(&self) -> Self {
+        SkipAnyConsumer {
+            base: self.base.split_off_left(),
+            ..*self
+        }
+    }
+
+    fn to_reducer(&self) -> Self::Reducer {
+        self.base.to_reducer()
+    }
+}
+
+struct SkipAnyFolder<'f, C> {
+    base: C,
+    count: &'f AtomicUsize,
+}
+
+fn checked_decrement(u: &AtomicUsize) -> bool {
+    u.fetch_update(Ordering::Relaxed, Ordering::Relaxed, |u| u.checked_sub(1))
+        .is_ok()
+}
+
+impl<'f, T, C> Folder<T> for SkipAnyFolder<'f, C>
+where
+    C: Folder<T>,
+{
+    type Result = C::Result;
+
+    fn consume(mut self, item: T) -> Self {
+        if !checked_decrement(self.count) {
+            self.base = self.base.consume(item);
+        }
+        self
+    }
+
+    fn consume_iter<I>(mut self, iter: I) -> Self
+    where
+        I: IntoIterator<Item = T>,
+    {
+        self.base = self.base.consume_iter(
+            iter.into_iter()
+                .skip_while(move |_| checked_decrement(self.count)),
+        );
+        self
+    }
+
+    fn complete(self) -> C::Result {
+        self.base.complete()
+    }
+
+    fn full(&self) -> bool {
+        self.base.full()
+    }
+}
diff --git a/src/iter/take_any.rs b/src/iter/take_any.rs
new file mode 100644
index 0000000..ce4631c
--- /dev/null
+++ b/src/iter/take_any.rs
@@ -0,0 +1,148 @@
+use super::plumbing::*;
+use super::*;
+use std::sync::atomic::{AtomicUsize, Ordering};
+
+/// `TakeAny` is an iterator that iterates over `n` elements from anywhere in `I`.
+/// This struct is created by the [`take_any()`] method on [`ParallelIterator`]
+///
+/// [`take_any()`]: trait.ParallelIterator.html#method.take_any
+/// [`ParallelIterator`]: trait.ParallelIterator.html
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[derive(Debug)]
+pub struct TakeAny<I: ParallelIterator> {
+    base: I,
+    count: AtomicUsize,
+}
+
+impl<I> TakeAny<I>
+where
+    I: ParallelIterator,
+{
+    /// Creates a new `TakeAny` iterator.
+    pub(super) fn new(base: I, count: usize) -> Self {
+        TakeAny {
+            base,
+            count: AtomicUsize::new(count),
+        }
+    }
+}
+
+impl<I, T> ParallelIterator for TakeAny<I>
+where
+    I: ParallelIterator<Item = T>,
+    T: Send,
+{
+    type Item = T;
+
+    fn drive_unindexed<C>(self, consumer: C) -> C::Result
+    where
+        C: UnindexedConsumer<Self::Item>,
+    {
+        let consumer1 = TakeAnyConsumer {
+            base: consumer,
+            count: &self.count,
+        };
+        self.base.drive_unindexed(consumer1)
+    }
+}
+
+/// ////////////////////////////////////////////////////////////////////////
+/// Consumer implementation
+
+struct TakeAnyConsumer<'f, C> {
+    base: C,
+    count: &'f AtomicUsize,
+}
+
+impl<'f, T, C> Consumer<T> for TakeAnyConsumer<'f, C>
+where
+    C: Consumer<T>,
+    T: Send,
+{
+    type Folder = TakeAnyFolder<'f, C::Folder>;
+    type Reducer = C::Reducer;
+    type Result = C::Result;
+
+    fn split_at(self, index: usize) -> (Self, Self, Self::Reducer) {
+        let (left, right, reducer) = self.base.split_at(index);
+        (
+            TakeAnyConsumer { base: left, ..self },
+            TakeAnyConsumer {
+                base: right,
+                ..self
+            },
+            reducer,
+        )
+    }
+
+    fn into_folder(self) -> Self::Folder {
+        TakeAnyFolder {
+            base: self.base.into_folder(),
+            count: self.count,
+        }
+    }
+
+    fn full(&self) -> bool {
+        self.count.load(Ordering::Relaxed) == 0 || self.base.full()
+    }
+}
+
+impl<'f, T, C> UnindexedConsumer<T> for TakeAnyConsumer<'f, C>
+where
+    C: UnindexedConsumer<T>,
+    T: Send,
+{
+    fn split_off_left(&self) -> Self {
+        TakeAnyConsumer {
+            base: self.base.split_off_left(),
+            ..*self
+        }
+    }
+
+    fn to_reducer(&self) -> Self::Reducer {
+        self.base.to_reducer()
+    }
+}
+
+struct TakeAnyFolder<'f, C> {
+    base: C,
+    count: &'f AtomicUsize,
+}
+
+fn checked_decrement(u: &AtomicUsize) -> bool {
+    u.fetch_update(Ordering::Relaxed, Ordering::Relaxed, |u| u.checked_sub(1))
+        .is_ok()
+}
+
+impl<'f, T, C> Folder<T> for TakeAnyFolder<'f, C>
+where
+    C: Folder<T>,
+{
+    type Result = C::Result;
+
+    fn consume(mut self, item: T) -> Self {
+        if checked_decrement(self.count) {
+            self.base = self.base.consume(item);
+        }
+        self
+    }
+
+    fn consume_iter<I>(mut self, iter: I) -> Self
+    where
+        I: IntoIterator<Item = T>,
+    {
+        self.base = self.base.consume_iter(
+            iter.into_iter()
+                .take_while(move |_| checked_decrement(self.count)),
+        );
+        self
+    }
+
+    fn complete(self) -> C::Result {
+        self.base.complete()
+    }
+
+    fn full(&self) -> bool {
+        self.count.load(Ordering::Relaxed) == 0 || self.base.full()
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
index e35160b..25a5e16 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -76,11 +76,6 @@
 //! [the `collections` from `std`]: https://doc.rust-lang.org/std/collections/index.html
 //! [`std`]: https://doc.rust-lang.org/std/
 //!
-//! # Targets without threading
-//!
-//! Rayon has limited support for targets without `std` threading implementations.
-//! See the [`rayon_core`] documentation for more information about its global fallback.
-//!
 //! # Other questions?
 //!
 //! See [the Rayon FAQ][faq].


Test patch:
diff --git a/rayon-core/src/broadcast/test.rs b/rayon-core/src/broadcast/test.rs
index 3ae11f7..a765cb0 100644
--- a/rayon-core/src/broadcast/test.rs
+++ b/rayon-core/src/broadcast/test.rs
@@ -12,7 +12,6 @@ fn broadcast_global() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn spawn_broadcast_global() {
     let (tx, rx) = crossbeam_channel::unbounded();
     crate::spawn_broadcast(move |ctx| tx.send(ctx.index()).unwrap());
@@ -23,7 +22,6 @@ fn spawn_broadcast_global() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn broadcast_pool() {
     let pool = ThreadPoolBuilder::new().num_threads(7).build().unwrap();
     let v = pool.broadcast(|ctx| ctx.index());
@@ -31,7 +29,6 @@ fn broadcast_pool() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn spawn_broadcast_pool() {
     let (tx, rx) = crossbeam_channel::unbounded();
     let pool = ThreadPoolBuilder::new().num_threads(7).build().unwrap();
@@ -43,7 +40,6 @@ fn spawn_broadcast_pool() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn broadcast_self() {
     let pool = ThreadPoolBuilder::new().num_threads(7).build().unwrap();
     let v = pool.install(|| crate::broadcast(|ctx| ctx.index()));
@@ -51,7 +47,6 @@ fn broadcast_self() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn spawn_broadcast_self() {
     let (tx, rx) = crossbeam_channel::unbounded();
     let pool = ThreadPoolBuilder::new().num_threads(7).build().unwrap();
@@ -63,7 +58,6 @@ fn spawn_broadcast_self() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn broadcast_mutual() {
     let count = AtomicUsize::new(0);
     let pool1 = ThreadPoolBuilder::new().num_threads(3).build().unwrap();
@@ -79,7 +73,6 @@ fn broadcast_mutual() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn spawn_broadcast_mutual() {
     let (tx, rx) = crossbeam_channel::unbounded();
     let pool1 = Arc::new(ThreadPoolBuilder::new().num_threads(3).build().unwrap());
@@ -97,7 +90,6 @@ fn spawn_broadcast_mutual() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn broadcast_mutual_sleepy() {
     let count = AtomicUsize::new(0);
     let pool1 = ThreadPoolBuilder::new().num_threads(3).build().unwrap();
@@ -116,7 +108,6 @@ fn broadcast_mutual_sleepy() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn spawn_broadcast_mutual_sleepy() {
     let (tx, rx) = crossbeam_channel::unbounded();
     let pool1 = Arc::new(ThreadPoolBuilder::new().num_threads(3).build().unwrap());
@@ -139,7 +130,6 @@ fn spawn_broadcast_mutual_sleepy() {
 }
 
 #[test]
-#[cfg_attr(not(panic = "unwind"), ignore)]
 fn broadcast_panic_one() {
     let count = AtomicUsize::new(0);
     let pool = ThreadPoolBuilder::new().num_threads(7).build().unwrap();
@@ -156,7 +146,6 @@ fn broadcast_panic_one() {
 }
 
 #[test]
-#[cfg_attr(not(panic = "unwind"), ignore)]
 fn spawn_broadcast_panic_one() {
     let (tx, rx) = crossbeam_channel::unbounded();
     let (panic_tx, panic_rx) = crossbeam_channel::unbounded();
@@ -177,7 +166,6 @@ fn spawn_broadcast_panic_one() {
 }
 
 #[test]
-#[cfg_attr(not(panic = "unwind"), ignore)]
 fn broadcast_panic_many() {
     let count = AtomicUsize::new(0);
     let pool = ThreadPoolBuilder::new().num_threads(7).build().unwrap();
@@ -194,7 +182,6 @@ fn broadcast_panic_many() {
 }
 
 #[test]
-#[cfg_attr(not(panic = "unwind"), ignore)]
 fn spawn_broadcast_panic_many() {
     let (tx, rx) = crossbeam_channel::unbounded();
     let (panic_tx, panic_rx) = crossbeam_channel::unbounded();
@@ -215,7 +202,6 @@ fn spawn_broadcast_panic_many() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn broadcast_sleep_race() {
     let test_duration = time::Duration::from_secs(1);
     let pool = ThreadPoolBuilder::new().num_threads(7).build().unwrap();
@@ -228,35 +214,3 @@ fn broadcast_sleep_race() {
         });
     }
 }
-
-#[test]
-fn broadcast_after_spawn_broadcast() {
-    let (tx, rx) = crossbeam_channel::unbounded();
-
-    // Queue a non-blocking spawn_broadcast.
-    crate::spawn_broadcast(move |ctx| tx.send(ctx.index()).unwrap());
-
-    // This blocking broadcast runs after all prior broadcasts.
-    crate::broadcast(|_| {});
-
-    // The spawn_broadcast **must** have run by now on all threads.
-    let mut v: Vec<_> = rx.try_iter().collect();
-    v.sort_unstable();
-    assert!(v.into_iter().eq(0..crate::current_num_threads()));
-}
-
-#[test]
-fn broadcast_after_spawn() {
-    let (tx, rx) = crossbeam_channel::bounded(1);
-
-    // Queue a regular spawn on a thread-local deque.
-    crate::registry::in_worker(move |_, _| {
-        crate::spawn(move || tx.send(22).unwrap());
-    });
-
-    // Broadcast runs after the local deque is empty.
-    crate::broadcast(|_| {});
-
-    // The spawn **must** have run by now.
-    assert_eq!(22, rx.try_recv().unwrap());
-}
diff --git a/rayon-core/src/join/test.rs b/rayon-core/src/join/test.rs
index b303dbc..e7f287f 100644
--- a/rayon-core/src/join/test.rs
+++ b/rayon-core/src/join/test.rs
@@ -47,7 +47,6 @@ fn sort() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn sort_in_pool() {
     let rng = seeded_rng();
     let mut data: Vec<u32> = rng.sample_iter(&Standard).take(12 * 1024).collect();
@@ -78,7 +77,6 @@ fn panic_propagate_both() {
 }
 
 #[test]
-#[cfg_attr(not(panic = "unwind"), ignore)]
 fn panic_b_still_executes() {
     let mut x = false;
     match unwind::halt_unwinding(|| join(|| panic!("Hello, world!"), || x = true)) {
@@ -88,7 +86,6 @@ fn panic_b_still_executes() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn join_context_both() {
     // If we're not in a pool, both should be marked stolen as they're injected.
     let (a_migrated, b_migrated) = join_context(|a| a.migrated(), |b| b.migrated());
@@ -97,7 +94,6 @@ fn join_context_both() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn join_context_neither() {
     // If we're already in a 1-thread pool, neither job should be stolen.
     let pool = ThreadPoolBuilder::new().num_threads(1).build().unwrap();
@@ -108,7 +104,6 @@ fn join_context_neither() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn join_context_second() {
     use std::sync::Barrier;
 
@@ -132,7 +127,6 @@ fn join_context_second() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn join_counter_overflow() {
     const MAX: u32 = 500_000;
 
diff --git a/rayon-core/src/scope/test.rs b/rayon-core/src/scope/test.rs
index ad8c4af..00dd18c 100644
--- a/rayon-core/src/scope/test.rs
+++ b/rayon-core/src/scope/test.rs
@@ -148,7 +148,6 @@ fn update_tree() {
 /// linearly with N. We test this by some unsafe hackery and
 /// permitting an approx 10% change with a 10x input change.
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn linear_stack_growth() {
     let builder = ThreadPoolBuilder::new().num_threads(1);
     let pool = builder.build().unwrap();
@@ -214,7 +213,6 @@ fn panic_propagate_nested_scope_spawn() {
 }
 
 #[test]
-#[cfg_attr(not(panic = "unwind"), ignore)]
 fn panic_propagate_still_execute_1() {
     let mut x = false;
     match unwind::halt_unwinding(|| {
@@ -229,7 +227,6 @@ fn panic_propagate_still_execute_1() {
 }
 
 #[test]
-#[cfg_attr(not(panic = "unwind"), ignore)]
 fn panic_propagate_still_execute_2() {
     let mut x = false;
     match unwind::halt_unwinding(|| {
@@ -244,7 +241,6 @@ fn panic_propagate_still_execute_2() {
 }
 
 #[test]
-#[cfg_attr(not(panic = "unwind"), ignore)]
 fn panic_propagate_still_execute_3() {
     let mut x = false;
     match unwind::halt_unwinding(|| {
@@ -259,7 +255,6 @@ fn panic_propagate_still_execute_3() {
 }
 
 #[test]
-#[cfg_attr(not(panic = "unwind"), ignore)]
 fn panic_propagate_still_execute_4() {
     let mut x = false;
     match unwind::halt_unwinding(|| {
@@ -297,7 +292,6 @@ macro_rules! test_order {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn lifo_order() {
     // In the absence of stealing, `scope()` runs its `spawn()` jobs in LIFO order.
     let vec = test_order!(scope => spawn);
@@ -306,7 +300,6 @@ fn lifo_order() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn fifo_order() {
     // In the absence of stealing, `scope_fifo()` runs its `spawn_fifo()` jobs in FIFO order.
     let vec = test_order!(scope_fifo => spawn_fifo);
@@ -341,7 +334,6 @@ macro_rules! test_nested_order {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn nested_lifo_order() {
     // In the absence of stealing, `scope()` runs its `spawn()` jobs in LIFO order.
     let vec = test_nested_order!(scope => spawn, scope => spawn);
@@ -350,7 +342,6 @@ fn nested_lifo_order() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn nested_fifo_order() {
     // In the absence of stealing, `scope_fifo()` runs its `spawn_fifo()` jobs in FIFO order.
     let vec = test_nested_order!(scope_fifo => spawn_fifo, scope_fifo => spawn_fifo);
@@ -359,7 +350,6 @@ fn nested_fifo_order() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn nested_lifo_fifo_order() {
     // LIFO on the outside, FIFO on the inside
     let vec = test_nested_order!(scope => spawn, scope_fifo => spawn_fifo);
@@ -371,7 +361,6 @@ fn nested_lifo_fifo_order() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn nested_fifo_lifo_order() {
     // FIFO on the outside, LIFO on the inside
     let vec = test_nested_order!(scope_fifo => spawn_fifo, scope => spawn);
@@ -414,7 +403,6 @@ macro_rules! test_mixed_order {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn mixed_lifo_order() {
     // NB: the end of the inner scope makes us execute some of the outer scope
     // before they've all been spawned, so they're not perfectly LIFO.
@@ -424,7 +412,6 @@ fn mixed_lifo_order() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn mixed_fifo_order() {
     let vec = test_mixed_order!(scope_fifo => spawn_fifo, scope_fifo => spawn_fifo);
     let expected = vec![-1, 0, -2, 1, -3, 2, 3];
@@ -432,7 +419,6 @@ fn mixed_fifo_order() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn mixed_lifo_fifo_order() {
     // NB: the end of the inner scope makes us execute some of the outer scope
     // before they've all been spawned, so they're not perfectly LIFO.
@@ -442,7 +428,6 @@ fn mixed_lifo_fifo_order() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn mixed_fifo_lifo_order() {
     let vec = test_mixed_order!(scope_fifo => spawn_fifo, scope => spawn);
     let expected = vec![-3, 0, -2, 1, -1, 2, 3];
@@ -568,7 +553,6 @@ fn scope_spawn_broadcast_nested() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn scope_spawn_broadcast_barrier() {
     let barrier = Barrier::new(8);
     let pool = ThreadPoolBuilder::new().num_threads(7).build().unwrap();
@@ -581,7 +565,6 @@ fn scope_spawn_broadcast_barrier() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn scope_spawn_broadcast_panic_one() {
     let count = AtomicUsize::new(0);
     let pool = ThreadPoolBuilder::new().num_threads(7).build().unwrap();
@@ -600,7 +583,6 @@ fn scope_spawn_broadcast_panic_one() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn scope_spawn_broadcast_panic_many() {
     let count = AtomicUsize::new(0);
     let pool = ThreadPoolBuilder::new().num_threads(7).build().unwrap();
diff --git a/rayon-core/src/spawn/test.rs b/rayon-core/src/spawn/test.rs
index b7a0535..761fafc 100644
--- a/rayon-core/src/spawn/test.rs
+++ b/rayon-core/src/spawn/test.rs
@@ -7,7 +7,6 @@ use super::{spawn, spawn_fifo};
 use crate::ThreadPoolBuilder;
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn spawn_then_join_in_worker() {
     let (tx, rx) = channel();
     scope(move |_| {
@@ -17,7 +16,6 @@ fn spawn_then_join_in_worker() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn spawn_then_join_outside_worker() {
     let (tx, rx) = channel();
     spawn(move || tx.send(22).unwrap());
@@ -25,7 +23,6 @@ fn spawn_then_join_outside_worker() {
 }
 
 #[test]
-#[cfg_attr(not(panic = "unwind"), ignore)]
 fn panic_fwd() {
     let (tx, rx) = channel();
 
@@ -57,7 +54,6 @@ fn panic_fwd() {
 /// still active asynchronous tasks. We expect the thread-pool to stay
 /// alive and executing until those threads are complete.
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn termination_while_things_are_executing() {
     let (tx0, rx0) = channel();
     let (tx1, rx1) = channel();
@@ -84,7 +80,6 @@ fn termination_while_things_are_executing() {
 }
 
 #[test]
-#[cfg_attr(not(panic = "unwind"), ignore)]
 fn custom_panic_handler_and_spawn() {
     let (tx, rx) = channel();
 
@@ -112,7 +107,6 @@ fn custom_panic_handler_and_spawn() {
 }
 
 #[test]
-#[cfg_attr(not(panic = "unwind"), ignore)]
 fn custom_panic_handler_and_nested_spawn() {
     let (tx, rx) = channel();
 
@@ -171,7 +165,6 @@ macro_rules! test_order {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn lifo_order() {
     // In the absence of stealing, `spawn()` jobs on a thread will run in LIFO order.
     let vec = test_order!(spawn, spawn);
@@ -180,7 +173,6 @@ fn lifo_order() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn fifo_order() {
     // In the absence of stealing, `spawn_fifo()` jobs on a thread will run in FIFO order.
     let vec = test_order!(spawn_fifo, spawn_fifo);
@@ -189,7 +181,6 @@ fn fifo_order() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn lifo_fifo_order() {
     // LIFO on the outside, FIFO on the inside
     let vec = test_order!(spawn, spawn_fifo);
@@ -201,7 +192,6 @@ fn lifo_fifo_order() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn fifo_lifo_order() {
     // FIFO on the outside, LIFO on the inside
     let vec = test_order!(spawn_fifo, spawn);
@@ -239,7 +229,6 @@ macro_rules! test_mixed_order {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn mixed_lifo_fifo_order() {
     let vec = test_mixed_order!(spawn, spawn_fifo);
     let expected = vec![3, -1, 2, -2, 1, -3, 0];
@@ -247,7 +236,6 @@ fn mixed_lifo_fifo_order() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn mixed_fifo_lifo_order() {
     let vec = test_mixed_order!(spawn_fifo, spawn);
     let expected = vec![0, -3, 1, -2, 2, -1, 3];
diff --git a/rayon-core/src/test.rs b/rayon-core/src/test.rs
index 25b8487..46d63a7 100644
--- a/rayon-core/src/test.rs
+++ b/rayon-core/src/test.rs
@@ -5,7 +5,6 @@ use std::sync::atomic::{AtomicUsize, Ordering};
 use std::sync::{Arc, Barrier};
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn worker_thread_index() {
     let pool = ThreadPoolBuilder::new().num_threads(22).build().unwrap();
     assert_eq!(pool.current_num_threads(), 22);
@@ -15,7 +14,6 @@ fn worker_thread_index() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn start_callback_called() {
     let n_threads = 16;
     let n_called = Arc::new(AtomicUsize::new(0));
@@ -42,7 +40,6 @@ fn start_callback_called() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn exit_callback_called() {
     let n_threads = 16;
     let n_called = Arc::new(AtomicUsize::new(0));
@@ -72,7 +69,6 @@ fn exit_callback_called() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn handler_panics_handled_correctly() {
     let n_threads = 16;
     let n_called = Arc::new(AtomicUsize::new(0));
@@ -123,7 +119,6 @@ fn handler_panics_handled_correctly() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn check_config_build() {
     let pool = ThreadPoolBuilder::new().num_threads(22).build().unwrap();
     assert_eq!(pool.current_num_threads(), 22);
@@ -139,7 +134,6 @@ fn check_error_send_sync() {
 
 #[allow(deprecated)]
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn configuration() {
     let start_handler = move |_| {};
     let exit_handler = move |_| {};
@@ -160,7 +154,6 @@ fn configuration() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn default_pool() {
     ThreadPoolBuilder::default().build().unwrap();
 }
@@ -169,7 +162,6 @@ fn default_pool() {
 /// the pool is done with them, allowing them to be used with rayon again
 /// later. e.g. WebAssembly want to have their own pool of available threads.
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn cleared_current_thread() -> Result<(), ThreadPoolBuildError> {
     let n_threads = 5;
     let mut handles = vec![];
diff --git a/rayon-core/src/thread_pool/test.rs b/rayon-core/src/thread_pool/test.rs
index aa9a4d3..ac750a6 100644
--- a/rayon-core/src/thread_pool/test.rs
+++ b/rayon-core/src/thread_pool/test.rs
@@ -16,7 +16,6 @@ fn panic_propagate() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn workers_stop() {
     let registry;
 
@@ -44,7 +43,6 @@ fn join_a_lot(n: usize) {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn sleeper_stop() {
     use std::{thread, time};
 
@@ -91,7 +89,6 @@ fn wait_for_counter(mut counter: Arc<AtomicUsize>) -> usize {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn failed_thread_stack() {
     // Note: we first tried to force failure with a `usize::MAX` stack, but
     // macOS and Windows weren't fazed, or at least didn't fail the way we want.
@@ -118,7 +115,6 @@ fn failed_thread_stack() {
 }
 
 #[test]
-#[cfg_attr(not(panic = "unwind"), ignore)]
 fn panic_thread_name() {
     let (start_count, start_handler) = count_handler();
     let (exit_count, exit_handler) = count_handler();
@@ -143,7 +139,6 @@ fn panic_thread_name() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn self_install() {
     let pool = ThreadPoolBuilder::new().num_threads(1).build().unwrap();
 
@@ -152,7 +147,6 @@ fn self_install() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn mutual_install() {
     let pool1 = ThreadPoolBuilder::new().num_threads(1).build().unwrap();
     let pool2 = ThreadPoolBuilder::new().num_threads(1).build().unwrap();
@@ -172,7 +166,6 @@ fn mutual_install() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn mutual_install_sleepy() {
     use std::{thread, time};
 
@@ -201,7 +194,6 @@ fn mutual_install_sleepy() {
 
 #[test]
 #[allow(deprecated)]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn check_thread_pool_new() {
     let pool = ThreadPool::new(crate::Configuration::new().num_threads(22)).unwrap();
     assert_eq!(pool.current_num_threads(), 22);
@@ -227,7 +219,6 @@ macro_rules! test_scope_order {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn scope_lifo_order() {
     let vec = test_scope_order!(scope => spawn);
     let expected: Vec<i32> = (0..10).rev().collect(); // LIFO -> reversed
@@ -235,7 +226,6 @@ fn scope_lifo_order() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn scope_fifo_order() {
     let vec = test_scope_order!(scope_fifo => spawn_fifo);
     let expected: Vec<i32> = (0..10).collect(); // FIFO -> natural order
@@ -260,7 +250,6 @@ macro_rules! test_spawn_order {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn spawn_lifo_order() {
     let vec = test_spawn_order!(spawn);
     let expected: Vec<i32> = (0..10).rev().collect(); // LIFO -> reversed
@@ -268,7 +257,6 @@ fn spawn_lifo_order() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn spawn_fifo_order() {
     let vec = test_spawn_order!(spawn_fifo);
     let expected: Vec<i32> = (0..10).collect(); // FIFO -> natural order
@@ -276,7 +264,6 @@ fn spawn_fifo_order() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn nested_scopes() {
     // Create matching scopes for every thread pool.
     fn nest<'scope, OP>(pools: &[ThreadPool], scopes: Vec<&Scope<'scope>>, op: OP)
@@ -313,7 +300,6 @@ fn nested_scopes() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn nested_fifo_scopes() {
     // Create matching fifo scopes for every thread pool.
     fn nest<'scope, OP>(pools: &[ThreadPool], scopes: Vec<&ScopeFifo<'scope>>, op: OP)
@@ -350,7 +336,6 @@ fn nested_fifo_scopes() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn in_place_scope_no_deadlock() {
     let pool = ThreadPoolBuilder::new().num_threads(1).build().unwrap();
     let (tx, rx) = channel();
@@ -366,7 +351,6 @@ fn in_place_scope_no_deadlock() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn in_place_scope_fifo_no_deadlock() {
     let pool = ThreadPoolBuilder::new().num_threads(1).build().unwrap();
     let (tx, rx) = channel();
diff --git a/rayon-core/tests/double_init_fail.rs b/rayon-core/tests/double_init_fail.rs
index 1591530..b3ddbeb 100644
--- a/rayon-core/tests/double_init_fail.rs
+++ b/rayon-core/tests/double_init_fail.rs
@@ -2,7 +2,6 @@ use rayon_core::ThreadPoolBuilder;
 use std::error::Error;
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn double_init_fail() {
     let result1 = ThreadPoolBuilder::new().build_global();
     assert!(result1.is_ok());
diff --git a/rayon-core/tests/init_zero_threads.rs b/rayon-core/tests/init_zero_threads.rs
index 3c1ad25..ebd73c5 100644
--- a/rayon-core/tests/init_zero_threads.rs
+++ b/rayon-core/tests/init_zero_threads.rs
@@ -1,7 +1,6 @@
 use rayon_core::ThreadPoolBuilder;
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn init_zero_threads() {
     ThreadPoolBuilder::new()
         .num_threads(0)
diff --git a/rayon-core/tests/scoped_threadpool.rs b/rayon-core/tests/scoped_threadpool.rs
index 534e8bb..db3d0b8 100644
--- a/rayon-core/tests/scoped_threadpool.rs
+++ b/rayon-core/tests/scoped_threadpool.rs
@@ -7,7 +7,6 @@ struct Local(i32);
 scoped_tls::scoped_thread_local!(static LOCAL: Local);
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn missing_scoped_tls() {
     LOCAL.set(&Local(42), || {
         let pool = ThreadPoolBuilder::new()
@@ -22,7 +21,6 @@ fn missing_scoped_tls() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn spawn_scoped_tls_threadpool() {
     LOCAL.set(&Local(42), || {
         LOCAL.with(|x| {
@@ -65,7 +63,6 @@ fn spawn_scoped_tls_threadpool() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn build_scoped_tls_threadpool() {
     LOCAL.set(&Local(42), || {
         LOCAL.with(|x| {
diff --git a/rayon-core/tests/stack_overflow_crash.rs b/rayon-core/tests/stack_overflow_crash.rs
index 7dcde43..e87e151 100644
--- a/rayon-core/tests/stack_overflow_crash.rs
+++ b/rayon-core/tests/stack_overflow_crash.rs
@@ -40,12 +40,10 @@ fn overflow_code() -> Option<i32> {
 }
 
 #[test]
-#[cfg_attr(not(any(unix, windows)), ignore)]
 fn stack_overflow_crash() {
     // First check that the recursive call actually causes a stack overflow,
     // and does not get optimized away.
     let status = run_ignored("run_with_small_stack");
-    assert!(!status.success());
     #[cfg(any(unix, windows))]
     assert_eq!(status.code(), overflow_code());
     #[cfg(target_os = "linux")]
diff --git a/src/iter/collect/test.rs b/src/iter/collect/test.rs
index 97bec3f..b5f676f 100644
--- a/src/iter/collect/test.rs
+++ b/src/iter/collect/test.rs
@@ -76,7 +76,6 @@ fn right_produces_items_with_no_complete() {
 
 // Complete is not called by the consumer. Hence,the collection vector is not fully initialized.
 #[test]
-#[cfg_attr(not(panic = "unwind"), ignore)]
 fn produces_items_with_no_complete() {
     let counter = DropCounter::default();
     let mut v = vec![];
@@ -274,7 +273,6 @@ fn right_panics() {
 // The left consumer produces fewer items while the right
 // consumer produces correct number; check that created elements are dropped
 #[test]
-#[cfg_attr(not(panic = "unwind"), ignore)]
 fn left_produces_fewer_items_drops() {
     let counter = DropCounter::default();
     let mut v = vec![];
diff --git a/src/iter/test.rs b/src/iter/test.rs
index c72068d..94323d7 100644
--- a/src/iter/test.rs
+++ b/src/iter/test.rs
@@ -468,7 +468,6 @@ fn check_cmp_gt_to_seq() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn check_cmp_short_circuit() {
     // We only use a single thread in order to make the short-circuit behavior deterministic.
     let pool = ThreadPoolBuilder::new().num_threads(1).build().unwrap();
@@ -498,7 +497,6 @@ fn check_cmp_short_circuit() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn check_partial_cmp_short_circuit() {
     // We only use a single thread to make the short-circuit behavior deterministic.
     let pool = ThreadPoolBuilder::new().num_threads(1).build().unwrap();
@@ -528,7 +526,6 @@ fn check_partial_cmp_short_circuit() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn check_partial_cmp_nan_short_circuit() {
     // We only use a single thread to make the short-circuit behavior deterministic.
     let pool = ThreadPoolBuilder::new().num_threads(1).build().unwrap();
diff --git a/tests/collect.rs b/tests/collect.rs
index bfb080c..48b80f6 100644
--- a/tests/collect.rs
+++ b/tests/collect.rs
@@ -6,7 +6,6 @@ use std::sync::atomic::Ordering;
 use std::sync::Mutex;
 
 #[test]
-#[cfg_attr(not(panic = "unwind"), ignore)]
 fn collect_drop_on_unwind() {
     struct Recorddrop<'a>(i64, &'a Mutex<Vec<i64>>);
 
@@ -62,7 +61,6 @@ fn collect_drop_on_unwind() {
 }
 
 #[test]
-#[cfg_attr(not(panic = "unwind"), ignore)]
 fn collect_drop_on_unwind_zst() {
     static INSERTS: AtomicUsize = AtomicUsize::new(0);
     static DROPS: AtomicUsize = AtomicUsize::new(0);
diff --git a/tests/cross-pool.rs b/tests/cross-pool.rs
index 835e2e2..f0a2128 100644
--- a/tests/cross-pool.rs
+++ b/tests/cross-pool.rs
@@ -2,7 +2,6 @@ use rayon::prelude::*;
 use rayon::ThreadPoolBuilder;
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn cross_pool_busy() {
     let pool1 = ThreadPoolBuilder::new().num_threads(1).build().unwrap();
     let pool2 = ThreadPoolBuilder::new().num_threads(1).build().unwrap();
diff --git a/tests/iter_panic.rs b/tests/iter_panic.rs
index c62a8db..37d4d6a 100644
--- a/tests/iter_panic.rs
+++ b/tests/iter_panic.rs
@@ -20,7 +20,6 @@ fn iter_panic() {
 }
 
 #[test]
-#[cfg_attr(not(panic = "unwind"), ignore)]
 fn iter_panic_fuse() {
     // We only use a single thread in order to make the behavior
     // of 'panic_fuse' deterministic
diff --git a/tests/named-threads.rs b/tests/named-threads.rs
index dadb37b..fd1b0be 100644
--- a/tests/named-threads.rs
+++ b/tests/named-threads.rs
@@ -4,7 +4,6 @@ use rayon::prelude::*;
 use rayon::*;
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn named_threads() {
     ThreadPoolBuilder::new()
         .thread_name(|i| format!("hello-name-test-{}", i))
diff --git a/tests/octillion.rs b/tests/octillion.rs
index 1af9ad8..cff2b11 100644
--- a/tests/octillion.rs
+++ b/tests/octillion.rs
@@ -68,14 +68,7 @@ fn two_threads<F: Send + FnOnce() -> R, R: Send>(f: F) -> R {
 }
 
 #[test]
-#[cfg_attr(
-    any(
-        not(target_pointer_width = "64"),
-        target_os = "emscripten",
-        target_family = "wasm"
-    ),
-    ignore
-)]
+#[cfg_attr(not(target_pointer_width = "64"), ignore)]
 fn find_last_octillion() {
     // It would be nice if `find_last` could prioritize the later splits,
     // basically flipping the `join` args, without needing indexed `rev`.
@@ -85,49 +78,32 @@ fn find_last_octillion() {
 }
 
 #[test]
-#[cfg_attr(
-    any(
-        not(target_pointer_width = "64"),
-        target_os = "emscripten",
-        target_family = "wasm"
-    ),
-    ignore
-)]
+#[cfg_attr(not(target_pointer_width = "64"), ignore)]
 fn find_last_octillion_inclusive() {
     let x = two_threads(|| octillion_inclusive().find_last(|_| true));
     assert_eq!(x, Some(OCTILLION));
 }
 
 #[test]
-#[cfg_attr(
-    any(
-        not(target_pointer_width = "64"),
-        target_os = "emscripten",
-        target_family = "wasm"
-    ),
-    ignore
-)]
+#[cfg_attr(not(target_pointer_width = "64"), ignore)]
 fn find_last_octillion_flat() {
     let x = two_threads(|| octillion_flat().find_last(|_| true));
     assert_eq!(x, Some(OCTILLION - 1));
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn find_any_octillion() {
     let x = two_threads(|| octillion().find_any(|x| *x > OCTILLION / 2));
     assert!(x.is_some());
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn find_any_octillion_flat() {
     let x = two_threads(|| octillion_flat().find_any(|x| *x > OCTILLION / 2));
     assert!(x.is_some());
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn filter_find_any_octillion() {
     let x = two_threads(|| {
         octillion()
@@ -138,7 +114,6 @@ fn filter_find_any_octillion() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn filter_find_any_octillion_flat() {
     let x = two_threads(|| {
         octillion_flat()
@@ -149,7 +124,6 @@ fn filter_find_any_octillion_flat() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn fold_find_any_octillion_flat() {
     let x = two_threads(|| octillion_flat().fold(|| (), |_, _| ()).find_any(|_| true));
     assert!(x.is_some());
diff --git a/tests/par_bridge_recursion.rs b/tests/par_bridge_recursion.rs
index 3a48ef1..4def0a9 100644
--- a/tests/par_bridge_recursion.rs
+++ b/tests/par_bridge_recursion.rs
@@ -4,7 +4,6 @@ use std::iter::once_with;
 const N: usize = 100_000;
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn par_bridge_recursion() {
     let pool = rayon::ThreadPoolBuilder::new()
         .num_threads(10)
diff --git a/tests/sort-panic-safe.rs b/tests/sort-panic-safe.rs
index 95ef88d..00a9731 100644
--- a/tests/sort-panic-safe.rs
+++ b/tests/sort-panic-safe.rs
@@ -8,12 +8,11 @@ use std::sync::atomic::AtomicUsize;
 use std::sync::atomic::Ordering::Relaxed;
 use std::thread;
 
-const ZERO: AtomicUsize = AtomicUsize::new(0);
-const LEN: usize = 20_000;
+static VERSIONS: AtomicUsize = AtomicUsize::new(0);
 
-static VERSIONS: AtomicUsize = ZERO;
-
-static DROP_COUNTS: [AtomicUsize; LEN] = [ZERO; LEN];
+lazy_static::lazy_static! {
+    static ref DROP_COUNTS: Vec<AtomicUsize> = (0..20_000).map(|_| AtomicUsize::new(0)).collect();
+}
 
 #[derive(Clone, Eq)]
 struct DropCounter {
@@ -118,7 +117,6 @@ macro_rules! test {
 thread_local!(static SILENCE_PANIC: Cell<bool> = Cell::new(false));
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
 fn sort_panic_safe() {
     let prev = panic::take_hook();
     panic::set_hook(Box::new(move |info| {