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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
//! Shared helpers for this crate's GPU-gated unit tests.
use OsString;
use panic;
use ;
use crateCudaRuntime;
/// Process-global lock serialising every test that reads or writes an
/// environment variable that gates production behaviour.
///
/// `cargo test` runs tests as parallel threads inside a **single process**, and
/// `std::env` is process-wide mutable state. A test that calls `set_var`/
/// `remove_var` therefore mutates state that *every other thread* observes. The
/// subtle half is the reader: a test that runs an env-gated code path and
/// asserts the **default** behaviour is just as exposed — it can observe another
/// thread's temporary `set_var` and fail — even though it never touches the
/// environment itself. Both writers and default-readers must serialise on the
/// same lock for the guard to close the race structurally rather than merely
/// shrink its window.
/// RAII guard that serialises environment-variable access across the crate's
/// unit tests and restores every variable it touched to its prior value on
/// drop.
///
/// Hold it for the **entire body** of any test that depends on an env-gated
/// code path — whether it mutates the variable or relies on its default. The
/// guard takes [`env_lock`] on construction and releases it on drop, so no two
/// such tests run concurrently and no mutation ever leaks past the test that
/// made it (the prior value is restored even if the test panics).
///
/// ```ignore
/// // A test that toggles a variable:
/// let mut env = EnvVarGuard::acquire();
/// env.set("MY_FLAG", "1");
/// // ... assertions ...
/// // drop restores MY_FLAG to whatever it was before.
///
/// // A test that depends on the *default* (unset) value must still lock:
/// let _env = EnvVarGuard::without_var("MY_FLAG");
/// ```
pub
/// Whether this host can construct a [`CudaRuntime`], probed exactly once.
///
/// `CudaRuntime::new` may *panic* rather than return `Err` when a CUDA library
/// is absent: cudarc's dynamic loader `expect()`s the shared object on first
/// use. The probe therefore runs under `catch_unwind` with the panic hook
/// silenced, so a GPU-gated test skips quietly on a host without libcuda
/// instead of spraying a panic message through the CPU-only suite.
///
/// The silencing must happen ONCE for the whole process. `set_hook` installs a
/// *process-global* hook, so the previous arrangement — every kernel test module
/// swapping the hook on every `runtime()` call — was doubly broken under the
/// default parallel harness:
///
/// * While one thread held the silencing hook, a genuine `assert!` failure on
/// another thread was swallowed, and libtest reported that test as `FAILED`
/// with an empty message and no location — leaving nothing to debug.
/// * Two overlapping `take_hook`/`set_hook` pairs lost updates: the second
/// thread could capture the *first* thread's silencing hook as its "previous"
/// and restore it, leaving panics muted for the rest of the run.
///
/// Behind a [`OnceLock`] the swap happens once instead of once per call. A
/// window remains — the one-time probe pays a CUDA context initialisation with
/// the hook silenced, and a CPU-only test panicking in exactly that window
/// would still lose its message — but it is bounded to a single startup
/// interval rather than recurring for every one of the several hundred
/// GPU-gated tests.
/// A freshly constructed runtime, or `None` when this host has no usable CUDA
/// device.
///
/// Each caller gets its own [`CudaRuntime`] — tests assert on per-runtime state
/// such as pool occupancy and capture status, so they must not share one. Only
/// the availability *probe* is memoized; once it has succeeded, construction
/// needs no `catch_unwind` because the panicking path has been ruled out.
pub