Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2397,7 +2397,6 @@ mod cell_data_tracking_tests {
// `evict_after_snapshot` uses `parallel::for_each`/`map_collect`, which call
// `block_in_place` internally and require a multi-threaded Tokio runtime.
#[tokio::test(flavor = "multi_thread")]
#[cfg_attr(target_family = "wasm", ignore = "parking_lot cannot block on wasm")]
async fn skip_never_cell_survives_eviction_without_modified_flag() {
// A Skip + evict="never" cell must be retained in memory by
// `drop_partial` (which keys on Evictability, not the modified flag), so
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,6 @@ mod tests {
}

#[test]
#[cfg_attr(target_family = "wasm", ignore = "parking_lot cannot block on wasm")]
fn snapshot_waits_for_ops_to_drain() {
let coord = Arc::new(SnapshotCoordinator::<Op>::new());

Expand Down Expand Up @@ -421,7 +420,6 @@ mod tests {
}

#[test]
#[cfg_attr(target_family = "wasm", ignore = "parking_lot cannot block on wasm")]
fn new_operation_blocks_during_snapshot() {
let coord = Arc::new(SnapshotCoordinator::<Op>::new());
let phase = coord.begin_snapshot();
Expand Down Expand Up @@ -465,7 +463,6 @@ mod tests {
}

#[test]
#[cfg_attr(target_family = "wasm", ignore = "parking_lot cannot block on wasm")]
fn suspend_point_lets_snapshot_proceed() {
let coord = Arc::new(SnapshotCoordinator::<Op>::new());
let g = coord.begin_operation();
Expand Down Expand Up @@ -546,7 +543,16 @@ mod tests {
/// fast-path missed-wakeup race when `OperationGuard::drop` does NOT
/// take the state mutex.
#[test]
#[cfg_attr(target_family = "wasm", ignore = "parking_lot cannot block on wasm")]
// Passes in isolation on wasm, but in a full-suite run it intermittently stops making progress
// partway through (its own watchdog reports `missed-wakeup race likely`) and the abort takes
// the whole test binary with it, since wasm is built `panic = abort`. Because progress
// halts rather than merely being slow, a longer watchdog does not help. The stall is not
// caused by any of the wasm changes — it reproduces on the parent layer too — so it is
// ignored here and tracked for a separate PR.
#[cfg_attr(
target_family = "wasm",
ignore = "stalls intermittently on wasm in a full-suite run; tracked separately"
)]
fn stress_no_missed_wakeups() {
run_with_timeout("stress_no_missed_wakeups", Duration::from_secs(60), || {
let coord = Arc::new(SnapshotCoordinator::<Op>::new());
Expand Down Expand Up @@ -615,10 +621,6 @@ mod tests {
}

#[test]
#[cfg_attr(
target_family = "wasm",
ignore = "parking_lot cannot block on wasm under this test's high contention"
)]
fn many_concurrent_ops_and_snapshots() {
// Stress test: hammer the protocol from many threads.
// The coordinator does not serialize concurrent snapshotters (callers
Expand Down Expand Up @@ -667,7 +669,6 @@ mod tests {
}

#[test]
#[cfg_attr(target_family = "wasm", ignore = "parking_lot cannot block on wasm")]
fn operations_waiting_tracks_blocked_operations() {
let coord = Arc::new(SnapshotCoordinator::<Op>::new());

Expand Down
10 changes: 0 additions & 10 deletions turbopack/crates/turbo-tasks-backend/src/backend/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1201,7 +1201,6 @@ mod tests {
// `end_snapshot` uses `parallel::for_each` which calls `block_in_place` internally,
// requiring a multi-threaded Tokio runtime.
#[tokio::test(flavor = "multi_thread")]
#[cfg_attr(target_family = "wasm", ignore = "parking_lot cannot block on wasm")]
async fn modify_during_snapshot_clears_live_modified_flags() {
let storage = Storage::new(2, true);
let task_id = non_transient_task(1);
Expand Down Expand Up @@ -1274,7 +1273,6 @@ mod tests {
/// unmodified-before-snapshot category is still the pre-snapshot state), clears pre-snapshot
/// flags, and promotes `data_modified_during_snapshot → data_modified`.
#[tokio::test(flavor = "multi_thread")]
#[cfg_attr(target_family = "wasm", ignore = "parking_lot cannot block on wasm")]
async fn modify_different_category_during_snapshot() {
let storage = Storage::new(2, true);
let task_id = non_transient_task(1);
Expand Down Expand Up @@ -1334,7 +1332,6 @@ mod tests {
/// persisted rather than retaining it until the whole snapshot is written. Either way the
/// entry must be gone from the map by the time the snapshot is consumed.
#[tokio::test(flavor = "multi_thread")]
#[cfg_attr(target_family = "wasm", ignore = "parking_lot cannot block on wasm")]
async fn drain_entries_removes_entry_from_map() {
let storage = Storage::new(2, true);
let task_id = non_transient_task(1);
Expand Down Expand Up @@ -1371,7 +1368,6 @@ mod tests {
/// In drain mode, fully consuming the iterators should release each drained shard's table
/// allocation entirely (reset-to-empty in `SnapshotShardIter::drop`), not just shrink it.
#[tokio::test(flavor = "multi_thread")]
#[cfg_attr(target_family = "wasm", ignore = "parking_lot cannot block on wasm")]
async fn drain_entries_releases_drained_shards() {
// dashmap requires at least 2 shards.
let storage = Storage::new(2, true);
Expand Down Expand Up @@ -1419,7 +1415,6 @@ mod tests {
/// the map is already empty when `take_snapshot` returns, and only the modified task is
/// yielded.
#[tokio::test(flavor = "multi_thread")]
#[cfg_attr(target_family = "wasm", ignore = "parking_lot cannot block on wasm")]
async fn drain_entries_removes_unmodified_during_take_snapshot() {
let storage = Storage::new(2, true);
let modified_id = non_transient_task(1);
Expand Down Expand Up @@ -1462,7 +1457,6 @@ mod tests {
}

#[tokio::test(flavor = "multi_thread")]
#[cfg_attr(target_family = "wasm", ignore = "parking_lot cannot block on wasm")]
async fn undo_non_snapshot_reverses_flag_and_counter() {
let storage = Storage::new(2, true);
let task_id = non_transient_task(1);
Expand All @@ -1487,7 +1481,6 @@ mod tests {
/// A second track on an already-modified category returns `NoChange`; undoing it is a no-op and
/// must NOT clear the real modification recorded by the first track.
#[tokio::test(flavor = "multi_thread")]
#[cfg_attr(target_family = "wasm", ignore = "parking_lot cannot block on wasm")]
async fn undo_nochange_preserves_prior_modification() {
let storage = Storage::new(2, true);
let task_id = non_transient_task(1);
Expand All @@ -1509,7 +1502,6 @@ mod tests {
/// Undo only reverses the category it tracked: tracking Data then Meta, undoing only the Meta
/// outcome must leave Data modified and the shard counter still non-zero.
#[tokio::test(flavor = "multi_thread")]
#[cfg_attr(target_family = "wasm", ignore = "parking_lot cannot block on wasm")]
async fn undo_only_reverses_its_own_category() {
let storage = Storage::new(2, true);
let task_id = non_transient_task(1);
Expand All @@ -1533,7 +1525,6 @@ mod tests {
/// snapshot, inserts a `None` marker into `snapshots` and sets the `_during_snapshot` bit.
/// Undo must remove the marker and clear the bit.
#[tokio::test(flavor = "multi_thread")]
#[cfg_attr(target_family = "wasm", ignore = "parking_lot cannot block on wasm")]
async fn undo_during_snapshot_true_false_removes_marker() {
let storage = Storage::new(2, true);
let task_id = non_transient_task(1);
Expand Down Expand Up @@ -1567,7 +1558,6 @@ mod tests {
/// the `_during_snapshot` bit, while leaving the pre-existing `modified` flag intact (it
/// belongs to the snapshot, not to this call).
#[tokio::test(flavor = "multi_thread")]
#[cfg_attr(target_family = "wasm", ignore = "parking_lot cannot block on wasm")]
async fn undo_during_snapshot_true_true_removes_copy_preserves_modified() {
let storage = Storage::new(2, true);
let task_id = non_transient_task(1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,10 @@ mod tests {
// This test is too slow to run under Miri.
#[cfg(not(miri))]
#[test]
#[cfg_attr(target_family = "wasm", ignore = "parking_lot cannot block on wasm")]
#[cfg_attr(
target_family = "wasm",
ignore = "stalls indefinitely under the Worker-based WASI host; tracked separately"
)]
fn stress_deadlock() {
const N: usize = 100000;
const THREADS: usize = 20;
Expand Down
11 changes: 11 additions & 0 deletions turbopack/crates/turbo-tasks/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,17 @@ unsize = { workspace = true }
[target.'cfg(not(target_family = "wasm"))'.dev-dependencies]
criterion = { workspace = true, features = ["async_tokio"] }

# `parking_lot_core` picks its thread parker in `thread_parker/mod.rs`. The working wasm parker
# (`wasm_atomic.rs`, built on `memory_atomic_wait32` / `memory_atomic_notify`) is selected only under
# `all(feature = "nightly", target_family = "wasm", target_feature = "atomics")`; otherwise it falls
# back to `wasm.rs`, whose `park()` is `panic!("Parking not supported on this platform")`.
#
# `wasm32-wasip1-threads` does have `target_feature = "atomics"`, so enabling the feature here is what
# makes contended locks block instead of panicking. Feature unification means declaring it once for
# wasm covers the whole wasm build; the feature is not enabled for any other target.
[target.'cfg(target_family = "wasm")'.dependencies]
parking_lot = { workspace = true, features = ["nightly"] }

[[bench]]
name = "mod"
harness = false
18 changes: 7 additions & 11 deletions turbopack/crates/turbo-tasks/src/parallel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,6 @@ mod tests {
use super::*;

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
#[cfg_attr(target_family = "wasm", ignore = "parking_lot cannot block on wasm")]
async fn test_parallel_for_each() {
let input = vec![1, 2, 3, 4, 5];
let sum = AtomicI32::new(0);
Expand All @@ -309,7 +308,6 @@ mod tests {
}

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
#[cfg_attr(target_family = "wasm", ignore = "parking_lot cannot block on wasm")]
async fn test_parallel_try_for_each() {
let input = vec![1, 2, 3, 4, 5];
let result = try_for_each(&input, |&x| {
Expand All @@ -324,11 +322,13 @@ mod tests {
}

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
// Without a working parker the scope does not wait for every chunk, so this fails with
// *incomplete* results rather than a panic.
#[cfg_attr(target_family = "wasm", ignore = "parking_lot cannot block on wasm")]
async fn test_parallel_try_for_each_mut() {
let mut input = vec![1, 2, 3, 4, 5];
// Match `good_chunk_size`'s target chunk count so every item gets its own chunk. This makes
// the exact mutation assertion independent of the machine's reported parallelism while
// still verifying that all chunks start even when earlier chunks return errors.
let item_count = available_parallelism().map_or(16, |count| count.get() * 4);
let max_value = i32::try_from(item_count).unwrap();
let mut input: Vec<_> = (1..=max_value).collect();
let result = try_for_each_mut(&mut input, |x| {
*x += 10;
if *x % 2 == 0 {
Expand All @@ -339,11 +339,10 @@ mod tests {
});
assert!(result.is_err());
assert_eq!(result.unwrap_err(), "Odd number 11 encountered");
assert_eq!(input, vec![11, 12, 13, 14, 15]);
assert_eq!(input, (11..=max_value + 10).collect::<Vec<_>>());
}

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
#[cfg_attr(target_family = "wasm", ignore = "parking_lot cannot block on wasm")]
async fn test_parallel_for_each_owned() {
let input = vec![1, 2, 3, 4, 5];
let sum = AtomicI32::new(0);
Expand All @@ -354,23 +353,20 @@ mod tests {
}

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
#[cfg_attr(target_family = "wasm", ignore = "parking_lot cannot block on wasm")]
async fn test_parallel_map_collect() {
let input = vec![1, 2, 3, 4, 5];
let result: Vec<_> = map_collect(&input, |&x| x * 2);
assert_eq!(result, vec![2, 4, 6, 8, 10]);
}

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
#[cfg_attr(target_family = "wasm", ignore = "parking_lot cannot block on wasm")]
async fn test_parallel_map_collect_owned() {
let input = vec![1, 2, 3, 4, 5];
let result: Vec<_> = map_collect_owned(input, |x| x * 2);
assert_eq!(result, vec![2, 4, 6, 8, 10]);
}

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
#[cfg_attr(target_family = "wasm", ignore = "parking_lot cannot block on wasm")]
async fn test_parallel_map_collect_owned_many() {
let input = vec![1; 1000];
let result: Vec<_> = map_collect_owned(input, |x| x * 2);
Expand Down
11 changes: 7 additions & 4 deletions turbopack/crates/turbo-tasks/src/priority_runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -699,7 +699,6 @@ mod tests {

#[cfg(not(miri))]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
#[cfg_attr(target_family = "wasm", ignore = "parking_lot cannot block on wasm")]
async fn test_cpu_bound_tasks() {
struct ExecutorImpl;

Expand Down Expand Up @@ -752,7 +751,6 @@ mod tests {
}

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
#[cfg_attr(target_family = "wasm", ignore = "parking_lot cannot block on wasm")]
async fn test_cpu_bound_with_yield_tasks() {
struct ExecutorImpl;

Expand Down Expand Up @@ -806,7 +804,6 @@ mod tests {
}

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
#[cfg_attr(target_family = "wasm", ignore = "parking_lot cannot block on wasm")]
async fn test_waiting_tasks() {
struct ExecutorImpl;

Expand Down Expand Up @@ -858,7 +855,13 @@ mod tests {
/// Each task waits on two barriers (start, finish). The release sequence
/// controls execution order deterministically.
#[test]
#[cfg_attr(target_family = "wasm", ignore = "parking_lot cannot block on wasm")]
// Same teardown deadlock as `scope::tests::test_scope_runs_in_parallel`: this orchestrates 20
// tasks through sync barriers and `spawn_blocking`, and dropping the runtime while those
// blocking threads are live hangs on wasm. Removed once the wasm runtime owns its lifetime.
#[cfg_attr(
target_family = "wasm",
ignore = "tokio runtime shutdown hangs on wasm while blocking threads are live"
)]
fn test_mixed_cpu_bound_and_waiting_tasks() {
tokio::runtime::Builder::new_multi_thread()
.worker_threads(2)
Expand Down
14 changes: 6 additions & 8 deletions turbopack/crates/turbo-tasks/src/scope_bounded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,6 @@ mod tests {
/// no helper can be scheduled; we assert the scope still finishes well before that deadline.
/// The deadline also guarantees the test fails cleanly instead of hanging.
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
#[cfg_attr(target_family = "wasm", ignore = "parking_lot cannot block on wasm")]
async fn test_scope_worker_threads_occupied() {
const WORKER_THREADS: usize = 2;
const JOBS: usize = 64;
Expand Down Expand Up @@ -341,7 +340,6 @@ mod tests {
/// On a `current_thread` runtime no helpers can be spawned and `block_in_place` is not allowed,
/// so the calling thread must drain the queue inline rather than panicking or hanging.
#[tokio::test(flavor = "current_thread")]
#[cfg_attr(target_family = "wasm", ignore = "parking_lot cannot block on wasm")]
async fn test_scope_current_thread_runtime() {
let results = tokio::task::spawn_blocking(|| {
scope_bounded(16, |scope| {
Expand All @@ -362,7 +360,12 @@ mod tests {
/// Helpers must actually add parallelism when threads are available: jobs that each block
/// briefly should complete in far less than their serial sum.
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
#[cfg_attr(target_family = "wasm", ignore = "parking_lot cannot block on wasm")]
// Node Worker startup makes the native timing bound too strict on wasm. A later layer uses a
// platform-aware bound that still distinguishes parallel from serial execution.
#[cfg_attr(
target_family = "wasm",
ignore = "timing bound is too strict for Node Worker startup"
)]
async fn test_scope_runs_in_parallel() {
const JOBS: usize = 16;
const PER_JOB: Duration = Duration::from_millis(50);
Expand Down Expand Up @@ -391,7 +394,6 @@ mod tests {
}

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
#[cfg_attr(target_family = "wasm", ignore = "parking_lot cannot block on wasm")]
async fn test_scope() {
let results = scope_bounded(1000, |scope| {
for i in 0..1000 {
Expand All @@ -406,7 +408,6 @@ mod tests {
}

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
#[cfg_attr(target_family = "wasm", ignore = "parking_lot cannot block on wasm")]
async fn test_empty_scope() {
let results = scope_bounded(0, |scope| {
if false {
Expand All @@ -417,7 +418,6 @@ mod tests {
}

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
#[cfg_attr(target_family = "wasm", ignore = "parking_lot cannot block on wasm")]
async fn test_single_task() {
let results = scope_bounded(1, |scope| {
scope.spawn(|| 42);
Expand All @@ -427,7 +427,6 @@ mod tests {
}

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
#[cfg_attr(target_family = "wasm", ignore = "parking_lot cannot block on wasm")]
async fn test_task_finish_before_scope() {
let results = scope_bounded(1, |scope| {
scope.spawn(|| 42);
Expand All @@ -438,7 +437,6 @@ mod tests {
}

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
#[cfg_attr(target_family = "wasm", ignore = "parking_lot cannot block on wasm")]
async fn test_task_finish_after_scope() {
let results = scope_bounded(1, |scope| {
scope.spawn(|| {
Expand Down
Loading
Loading