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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
//! OS primitive layer (mirrors upstream `src/prim/*`, plan §6). One backend per
//! platform, selected at compile time; under miri a registry-backed [`mock`]
//! stands in so the layers above stay testable where FFI cannot run (gate G4).
//!
//! This module is one of the few allowed `unsafe` (plan §6 policy): every block
//! carries its SAFETY invariant, and everything above talks to the safe-ish
//! surface in [`crate::os`].
use windows as sys;
use unix as sys;
// Wasm is neither `windows` nor `unix`, so it needs its own arm: one linear
// memory that only grows, no page protection, no clock, one thread.
use wasm as sys;
use mock as sys;
// A target with no OS at all — a microcontroller, where memory is a region the
// linker reserved (P1 of `docs/plans/small-metal.md`). This is the fifth arm
// P0 found missing: `riscv32imac-unknown-none-elf` is none of the four above,
// so before this existed no `sys` was named at all and every call through the
// seam failed together.
//
// ALWAYS COMPILED, so it is type-checked and unit-tested on the host;
// SELECTED only where no arm above matches, so no host build changes.
use fixed as sys;
use c_void;
/// OS error code (`GetLastError` on Windows, `errno` on unix, synthetic in mock).
pub type PrimError = u32;
/// Static memory-subsystem facts, queried once at startup (`_mi_prim_mem_init`).
/// Whether [`free`] actually returns memory to the host.
///
/// True everywhere except wasm: `munmap` and `VirtualFree(MEM_RELEASE)` both
/// release the whole mapping (only PARTIAL free differs between them — that is
/// [`MemConfig::has_partial_free`], a different property). On wasm linear
/// memory can only grow, so [`free`] is a no-op and a mapping handed to it
/// would otherwise be unreachable forever. [`crate::os::free`] keys on this to
/// hand such blocks to [`crate::arena::adopt_os_block`] instead, which is the
/// allocator's ONLY recycling layer on such a platform — the segment cache
/// this role is sometimes attributed to does not exist (upstream mimalloc v2
/// deleted it when arenas replaced it, and this remake followed).
///
/// A `const`, not a `MemConfig` field, so the adoption path folds away
/// entirely on every platform whose free works.
pub const FREE_RETURNS_MEMORY: bool = !cfg!;
/// Result of a successful [`alloc`].
/// Query static memory configuration.
/// Reserve (and optionally commit) `size` bytes aligned to `try_alignment`.
///
/// `size` must be page-multiple and > 0; `try_alignment` a power of two.
/// `allow_large` permits (but never requires) large-page backing.
///
/// # Safety
/// Returned memory is unmanaged: caller owns the range and must eventually
/// [`free`] it with the same base and size.
pub unsafe
/// Release a mapping obtained from [`alloc`].
///
/// # Safety
/// `ptr`/`size` must denote exactly one prior [`alloc`] result (whole mapping —
/// partial free only where `MemConfig::has_partial_free`), not yet freed.
pub unsafe
/// Commit a page-aligned range inside a reservation. Returns whether the
/// committed range is known-zero.
///
/// # Safety
/// Range must lie inside a live [`alloc`] mapping, page-aligned.
pub unsafe
/// Decommit a page-aligned range. Returns whether a later [`commit`] is
/// required before touching it again (Windows: yes; unix `MADV_DONTNEED`: no).
///
/// # Safety
/// Range must lie inside a live [`alloc`] mapping, page-aligned; contents lost.
pub unsafe
/// Tell the OS the range's contents are dead but keep it committed
/// (`MEM_RESET` / `MADV_FREE`). Contents afterwards are undefined.
///
/// # Safety
/// Range must lie inside a live, committed mapping, page-aligned.
pub unsafe
/// Toggle no-access protection on a page-aligned range (guard pages, M8).
///
/// # Safety
/// Range must lie inside a live, committed mapping; caller must not touch a
/// protected range until unprotected.
pub unsafe
/// Whether `[ptr, ptr+size)` is reserved or committed by the OS.
///
/// Used by `manage_os_memory_ex` so an unmapped lie cannot become an arena
/// (OH-rusty_alloc-201). Best-effort: a racing unmap can flip the answer.
/// Number of NUMA nodes (≥ 1). M1 returns the real count on Windows, 1 on
/// unix (sysfs parsing lands with arenas in M6).
/// Copy the value of the environment variable `name` — NUL-terminated ASCII —
/// into `out`, **without allocating** (`_mi_prim_getenv`). `Some(len)` with the
/// value's byte length when the variable is set and fits; `None` when it is
/// unset, empty on Windows (the API reports both as 0 and upstream's prim
/// treats both as unset), or longer than `out`.
///
/// This exists because `options.rs` read the environment through
/// `std::env::var`, whose key and value are both owned `String`s: 38 options
/// x 2 prefixes made **251 allocations through the global allocator on the
/// first allocation of every process** — inside the heap that was being set
/// up (`docs/plans/youslowbro.md` §4). Hosted platforms only: a firmware has
/// no environment, wasm has no raw `getenv`, and Miri interprets `std::env`
/// itself, so `options.rs` keeps a `std::env` fallback for those.
/// Call `f` with a pointer to every `NAME=VALUE` entry of the process
/// environment, in order, each NUL-terminated — one walk of `environ`, without
/// allocating. Linux only (glibc and musl export `environ`; a macOS dylib has
/// to go through `_NSGetEnviron`, and Windows has no such block of C strings).
///
/// For `options.rs`, which needs 38 options under two prefixes: as 76
/// [`getenv`] calls that is 76 walks of the whole environment, 17,372
/// instructions inside libc and 27,011 inclusive on the first allocation of
/// every process — 2 % of a one-line `sort` (callgrind). One walk that looks
/// only at entries starting with either prefix does the same job.
/// Cheap unique id of the calling thread (the heap-ownership key from M4).
/// Monotonic clock in nanoseconds (purge delays, stats).
/// Platform-native TLS destructor signature. On x86-64/aarch64 the `"system"`
/// and `"C"` ABIs coincide; the alias exists so each backend hands its OS the
/// exact type it expects.
pub type TlsDtor = unsafe extern "system" fn;
/// Platform-native TLS destructor signature (pthread form).
pub type TlsDtor = unsafe extern "C" fn;
/// A dynamically-created TLS slot whose destructor runs at thread exit with
/// the slot's value, if non-null (`FlsAlloc` / `pthread_key_create`). This is
/// the hook `mi_thread_done` hangs off in M4.
;
// SAFETY: a TLS slot handle is an index into per-thread storage; sharing the
// handle across threads is the entire point (each thread sees its own value).
unsafe
// SAFETY: as above — get/set only touch calling-thread state.
unsafe
/// Round `n` up to a multiple of power-of-two `align`.
pub const
/// Checked sibling of [`align_up`]. `None` when `n + align - 1` overflows
/// (OH-rusty_alloc-29). Only the Windows backend's large-page path rounds a
/// caller size up by an OS-reported unit; the others add before they align.
pub