1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
//! Real-OS-thread free-list conservation test — the multi-threaded coverage
//! `loom_aba.rs` structurally cannot provide.
//!
//! `loom_aba.rs` is exhaustive but tiny: every model there explores a small
//! bounded state space rather than running real time. This file covers the
//! complementary regime: a fixed, modest number of REAL OS threads hammering
//! a SHARED stack for many iterations and asserts free-list conservation.
//! It deliberately does not require a particular CAS-loss count: a real OS
//! scheduler may serialize otherwise-correct workers. Loom models separately
//! force and assert both retry branches, while `backoff_oracle.rs` checks the
//! local backoff progression and saturation deterministically. This test
//! checks the same conservation property at real-thread scale.
//!
//! Discipline mirrors `benches/tagged_index_stack_bench.rs`'s
//! `contention/churn` phase exactly: every thread pops WHATEVER is currently
//! on top (which may be another thread's index, under real contention) and
//! immediately re-pushes EXACTLY that value — never a locally invented index.
//! Re-pushing anything else violates `push_index`'s documented caller contract
//! ("index must NOT already be reachable from ANY stack that reads and
//! writes the same link cells") and would corrupt
//! the free-list independent of any bug this test exists to catch.
//!
//! Not a loom model (`#![cfg(not(loom))]`) — this is a normal `cargo test`
//! file exercising real OS threads at real scale, which loom cannot do (loom
//! replaces `std`'s atomics/threads with its own model-checked stand-ins and
//! only explores a small bounded state space).
use thread;
use ArrayIndexStack;
/// Same width as the bench and the rest of this crate's test suite; the fused
/// `ArrayIndexStack` owns its head and its `ArrayLinks` links together.
type Stack = LINKS_SIZE as usize }>;
/// Number of indices in the `ArrayLinks` backing store, and the exact
/// multiset seeded onto the stack before the threaded phase. Kept modest per
/// CLAUDE.md's "Speed: short scenario by default" convention.
const LINKS_SIZE: u32 = 64;
/// Real OS threads racing the shared stack concurrently.
const NUM_THREADS: usize = 8;
/// Pop-then-repush iterations per thread. `NUM_THREADS * ITERS_PER_THREAD`
/// (1.6M total pop/push pairs). The scale makes contention
/// likely on ordinary multi-core hosts, but no assertion depends on that
/// scheduler outcome.
const ITERS_PER_THREAD: u32 = 200_000;
/// One full contended round: `NUM_THREADS` real OS threads, each running
/// `ITERS_PER_THREAD` pop-then-immediately-repush iterations against the
/// shared stack. Pure free-list churn — every thread pops WHATEVER is
/// currently on top (which may be another thread's index, under real
/// contention) and immediately re-pushes EXACTLY that value — so it neither
/// adds nor removes anything from the stack, and running it more than once
/// cannot break the conservation check.
/// N threads x M iterations of pop-then-immediately-repush-exactly-what-you-
/// popped against a shared, prefilled stack, followed by a full drain and an
/// exact-multiset check: the classic Treiber free-list conservation property
/// (no index lost, none duplicated) under REAL contention.