tikv_jemalloc_sys/lib.rs
1//! Rust bindings to the `jemalloc` C library.
2//!
3//! `jemalloc` is a general purpose memory allocation, its documentation
4//! can be found here:
5//!
6//! * [API documentation][jemalloc_docs]
7//! * [Wiki][jemalloc_wiki] (design documents, presentations, profiling, debugging, tuning, ...)
8//!
9//! `jemalloc` exposes both a standard and a non-standard API.
10//!
11//! # Standard API
12//!
13//! The standard API includes: the [`malloc`], [`calloc`], [`realloc`], and
14//! [`free`], which conform to to ISO/IEC 9899:1990 (“ISO C90”),
15//! [`posix_memalign`] which conforms to conforms to POSIX.1-2016, and
16//! [`aligned_alloc`].
17//!
18//! Note that these standard leave some details as _implementation defined_.
19//! This docs document this behavior for `jemalloc`, but keep in mind that other
20//! standard-conforming implementations of these functions in other allocators
21//! might behave slightly different.
22//!
23//! # Non-Standard API
24//!
25//! The non-standard API includes: [`mallocx`], [`rallocx`], [`xallocx`],
26//! [`sallocx`], [`dallocx`], [`sdallocx`], and [`nallocx`]. These functions all
27//! have a `flags` argument that can be used to specify options. Use bitwise or
28//! `|` to specify one or more of the following: [`MALLOCX_LG_ALIGN`],
29//! [`MALLOCX_ALIGN`], [`MALLOCX_ZERO`], [`MALLOCX_TCACHE`],
30//! [`MALLOCX_TCACHE_NONE`], and [`MALLOCX_ARENA`].
31//!
32//! # Environment variables
33//!
34//! The `MALLOC_CONF` environment variable affects the execution of the allocation functions.
35//!
36//! For the documentation of the [`MALLCTL` namespace visit the jemalloc
37//! documenation][jemalloc_mallctl].
38//!
39//! [jemalloc_docs]: http://jemalloc.net/jemalloc.3.html
40//! [jemalloc_wiki]: https://github.com/jemalloc/jemalloc/wiki
41//! [jemalloc_mallctl]: http://jemalloc.net/jemalloc.3.html#mallctl_namespace
42#![no_std]
43#![allow(non_snake_case, non_camel_case_types)]
44// TODO: rename the following lint on next minor bump
45#![allow(renamed_and_removed_lints)]
46#![deny(missing_docs, broken_intra_doc_links)]
47
48use libc::{c_char, c_int, c_uint, c_void, size_t};
49
50// jemalloc uses `stdbool.h` to define `bool` for which the Rust equivalent is `bool`.
51// However jemalloc also has its own `stdbool.h` that it uses when compiling with MSVC,
52// and this header defines `bool` as `BOOL` which in turn is `int`.
53#[cfg(target_env = "msvc")]
54type c_bool = c_int;
55#[cfg(not(target_env = "msvc"))]
56type c_bool = bool;
57
58/// Align the memory allocation to start at an address that is a
59/// multiple of `1 << la`.
60///
61/// # Safety
62///
63/// It does not validate that `la` is within the valid range.
64#[inline]
65pub const fn MALLOCX_LG_ALIGN(la: usize) -> c_int {
66 la as c_int
67}
68
69/// Align the memory allocation to start at an address that is a multiple of `align`,
70/// where a is a power of two.
71///
72/// # Safety
73///
74/// This macro does not validate that a is a power of 2.
75#[inline]
76pub const fn MALLOCX_ALIGN(aling: usize) -> c_int {
77 aling.trailing_zeros() as c_int
78}
79
80/// Initialize newly allocated memory to contain zero bytes.
81///
82/// In the growing reallocation case, the real size prior to reallocation
83/// defines the boundary between untouched bytes and those that are initialized
84/// to contain zero bytes.
85///
86/// If this option is not set, newly allocated memory is uninitialized.
87pub const MALLOCX_ZERO: c_int = 0x40;
88
89/// Use the thread-specific cache (_tcache_) specified by the identifier `tc`.
90///
91/// # Safety
92///
93/// `tc` must have been acquired via the `tcache.create mallctl`. This function
94/// does not validate that `tc` specifies a valid identifier.
95#[inline]
96pub const fn MALLOCX_TCACHE(tc: usize) -> c_int {
97 tc.wrapping_add(2).wrapping_shl(8) as c_int
98}
99
100/// Do not use a thread-specific cache (_tcache_).
101///
102/// Unless `MALLOCX_TCACHE(tc)` or `MALLOCX_TCACHE_NONE` is specified, an
103/// automatically managed _tcache_ will be used under many circumstances.
104///
105/// # Safety
106///
107/// This option cannot be used in the same `flags` argument as
108/// `MALLOCX_TCACHE(tc)`.
109// FIXME: This should just be a const.
110pub const MALLOCX_TCACHE_NONE: c_int = MALLOCX_TCACHE((-1isize) as usize);
111
112/// Use the arena specified by the index `a`.
113///
114/// This option has no effect for regions that were allocated via an arena other
115/// than the one specified.
116///
117/// # Safety
118///
119/// This function does not validate that `a` specifies an arena index in the
120/// valid range.
121#[inline]
122pub const fn MALLOCX_ARENA(a: usize) -> c_int {
123 (a as c_int).wrapping_add(1).wrapping_shl(20)
124}
125
126extern "C" {
127 /// Allocates `size` bytes of uninitialized memory.
128 ///
129 /// It returns a pointer to the start (lowest byte address) of the allocated
130 /// space. This pointer is suitably aligned so that it may be assigned to a
131 /// pointer to any type of object and then used to access such an object in
132 /// the space allocated until the space is explicitly deallocated. Each
133 /// yielded pointer points to an object disjoint from any other object.
134 ///
135 /// If the `size` of the space requested is zero, either a null pointer is
136 /// returned, or the behavior is as if the `size` were some nonzero value,
137 /// except that the returned pointer shall not be used to access an object.
138 ///
139 /// # Errors
140 ///
141 /// If the space cannot be allocated, a null pointer is returned and `errno`
142 /// is set to `ENOMEM`.
143 #[cfg_attr(prefixed, link_name = "_rjem_malloc")]
144 pub fn malloc(size: size_t) -> *mut c_void;
145 /// Allocates zero-initialized space for an array of `number` objects, each
146 /// of whose size is `size`.
147 ///
148 /// The result is identical to calling [`malloc`] with an argument of
149 /// `number * size`, with the exception that the allocated memory is
150 /// explicitly initialized to _zero_ bytes.
151 ///
152 /// Note: zero-initialized memory need not be the same as the
153 /// representation of floating-point zero or a null pointer constant.
154 #[cfg_attr(prefixed, link_name = "_rjem_calloc")]
155 pub fn calloc(number: size_t, size: size_t) -> *mut c_void;
156
157 /// Allocates `size` bytes of memory at an address which is a multiple of
158 /// `alignment` and is placed in `*ptr`.
159 ///
160 /// If `size` is zero, then the value placed in `*ptr` is either null, or
161 /// the behavior is as if the `size` were some nonzero value, except that
162 /// the returned pointer shall not be used to access an object.
163 ///
164 /// # Errors
165 ///
166 /// On success, it returns zero. On error, the value of `errno` is _not_ set,
167 /// `*ptr` is not modified, and the return values can be:
168 ///
169 /// - `EINVAL`: the `alignment` argument was not a power-of-two or was not a multiple of
170 /// `mem::size_of::<*const c_void>()`.
171 /// - `ENOMEM`: there was insufficient memory to fulfill the allocation request.
172 ///
173 /// # Safety
174 ///
175 /// The behavior is _undefined_ if:
176 ///
177 /// * `ptr` is null.
178 #[cfg_attr(prefixed, link_name = "_rjem_posix_memalign")]
179 pub fn posix_memalign(ptr: *mut *mut c_void, alignment: size_t, size: size_t) -> c_int;
180
181 /// Allocates `size` bytes of memory at an address which is a multiple of
182 /// `alignment`.
183 ///
184 /// If the `size` of the space requested is zero, either a null pointer is
185 /// returned, or the behavior is as if the `size` were some nonzero value,
186 /// except that the returned pointer shall not be used to access an object.
187 ///
188 /// # Errors
189 ///
190 /// Returns null if the request fails.
191 ///
192 /// # Safety
193 ///
194 /// The behavior is _undefined_ if:
195 ///
196 /// * `alignment` is not a power-of-two
197 /// * `size` is not an integral multiple of `alignment`
198 #[cfg_attr(prefixed, link_name = "_rjem_aligned_alloc")]
199 pub fn aligned_alloc(alignment: size_t, size: size_t) -> *mut c_void;
200
201 /// Resizes the previously-allocated memory region referenced by `ptr` to
202 /// `size` bytes.
203 ///
204 /// Deallocates the old object pointed to by `ptr` and returns a pointer to
205 /// a new object that has the size specified by `size`. The contents of the
206 /// new object are the same as that of the old object prior to deallocation,
207 /// up to the lesser of the new and old sizes.
208 ///
209 /// The memory in the new object beyond the size of the old object is
210 /// uninitialized.
211 ///
212 /// The returned pointer to a new object may have the same value as a
213 /// pointer to the old object, but [`realloc`] may move the memory
214 /// allocation, resulting in a different return value than `ptr`.
215 ///
216 /// If `ptr` is null, [`realloc`] behaves identically to [`malloc`] for the
217 /// specified size.
218 ///
219 /// If the size of the space requested is zero, the behavior is
220 /// implementation-defined: either a null pointer is returned, or the
221 /// behavior is as if the size were some nonzero value, except that the
222 /// returned pointer shall not be used to access an object # Errors
223 ///
224 /// # Errors
225 ///
226 /// If memory for the new object cannot be allocated, the old object is not
227 /// deallocated, its value is unchanged, [`realloc`] returns null, and
228 /// `errno` is set to `ENOMEM`.
229 ///
230 /// # Safety
231 ///
232 /// The behavior is _undefined_ if:
233 ///
234 /// * `ptr` does not match a pointer previously returned by the memory
235 /// allocation functions of this crate, or
236 /// * the memory region referenced by `ptr` has been deallocated.
237 #[cfg_attr(prefixed, link_name = "_rjem_realloc")]
238 pub fn realloc(ptr: *mut c_void, size: size_t) -> *mut c_void;
239
240 /// Deallocates previously-allocated memory region referenced by `ptr`.
241 ///
242 /// This makes the space available for future allocations.
243 ///
244 /// If `ptr` is null, no action occurs.
245 ///
246 /// # Safety
247 ///
248 /// The behavior is _undefined_ if:
249 ///
250 /// * `ptr` does not match a pointer earlier returned by the memory
251 /// allocation functions of this crate, or
252 /// * the memory region referenced by `ptr` has been deallocated.
253 #[cfg_attr(prefixed, link_name = "_rjem_free")]
254 pub fn free(ptr: *mut c_void);
255
256 /// Deallocates previously-allocated memory region referenced by `ptr`.
257 ///
258 /// This makes the space available for future allocations.
259 ///
260 /// If `ptr` is null, no action occurs.
261 ///
262 /// # Safety
263 ///
264 /// The behavior is _undefined_ if:
265 ///
266 /// * `ptr` does not match a pointer earlier returned by the memory
267 /// allocation functions of this crate, or
268 /// * the memory region referenced by `ptr` has been deallocated, or
269 /// * `ptr` is returned by `aligned_alloc`.
270 #[cfg_attr(prefixed, link_name = "_rjem_free_sized")]
271 pub fn free_sized(ptr: *mut c_void, size: size_t);
272
273 /// Deallocates previously-allocated memory region referenced by `ptr`.
274 ///
275 /// This makes the space available for future allocations.
276 ///
277 /// If `ptr` is null, no action occurs.
278 ///
279 /// # Safety
280 ///
281 /// The behavior is _undefined_ if:
282 ///
283 /// * `ptr` does not match a pointer earlier returned by `aligned_alloc`,
284 /// or `alignment` and `size` do not match the values passed to
285 /// `aligned_alloc`, or
286 /// * the memory region referenced by `ptr` has been deallocated.
287 #[cfg_attr(prefixed, link_name = "_rjem_free_aligned_sized")]
288 pub fn free_aligned_sized(ptr: *mut c_void, alignment: size_t, size: size_t);
289
290 /// Allocates at least `size` bytes of memory according to `flags`.
291 ///
292 /// It returns a pointer to the start (lowest byte address) of the allocated
293 /// space. This pointer is suitably aligned so that it may be assigned to a
294 /// pointer to any type of object and then used to access such an object in
295 /// the space allocated until the space is explicitly deallocated. Each
296 /// yielded pointer points to an object disjoint from any other object.
297 ///
298 /// # Errors
299 ///
300 /// On success it returns a non-null pointer. A null pointer return value
301 /// indicates that insufficient contiguous memory was available to service
302 /// the allocation request.
303 ///
304 /// # Safety
305 ///
306 /// The behavior is _undefined_ if `size == 0`.
307 #[cfg_attr(prefixed, link_name = "_rjem_mallocx")]
308 pub fn mallocx(size: size_t, flags: c_int) -> *mut c_void;
309
310 /// Resizes the previously-allocated memory region referenced by `ptr` to be
311 /// at least `size` bytes.
312 ///
313 /// Deallocates the old object pointed to by `ptr` and returns a pointer to
314 /// a new object that has the size specified by `size`. The contents of the
315 /// new object are the same as that of the old object prior to deallocation,
316 /// up to the lesser of the new and old sizes.
317 ///
318 /// The the memory in the new object beyond the size of the old object is
319 /// obtained according to `flags` (it might be uninitialized).
320 ///
321 /// The returned pointer to a new object may have the same value as a
322 /// pointer to the old object, but [`rallocx`] may move the memory
323 /// allocation, resulting in a different return value than `ptr`.
324 ///
325 /// # Errors
326 ///
327 /// On success it returns a non-null pointer. A null pointer return value
328 /// indicates that insufficient contiguous memory was available to service
329 /// the allocation request. In this case, the old object is not
330 /// deallocated, and its value is unchanged.
331 ///
332 /// # Safety
333 ///
334 /// The behavior is _undefiend_ if:
335 ///
336 /// * `size == 0`, or
337 /// * `ptr` does not match a pointer earlier returned by
338 /// the memory allocation functions of this crate, or
339 /// * the memory region referenced by `ptr` has been deallocated.
340 #[cfg_attr(prefixed, link_name = "_rjem_rallocx")]
341 pub fn rallocx(ptr: *mut c_void, size: size_t, flags: c_int) -> *mut c_void;
342
343 /// Resizes the previously-allocated memory region referenced by `ptr` _in
344 /// place_ to be at least `size` bytes, returning the real size of the
345 /// allocation.
346 ///
347 /// Deallocates the old object pointed to by `ptr` and sets `ptr` to a new
348 /// object that has the size returned; the old a new objects share the same
349 /// base address. The contents of the new object are the same as that of the
350 /// old object prior to deallocation, up to the lesser of the new and old
351 /// sizes.
352 ///
353 /// If `extra` is non-zero, an attempt is made to resize the allocation to
354 /// be at least `size + extra` bytes. Inability to allocate the `extra`
355 /// bytes will not by itself result in failure to resize.
356 ///
357 /// The memory in the new object beyond the size of the old object is
358 /// obtained according to `flags` (it might be uninitialized).
359 ///
360 /// # Errors
361 ///
362 /// If the allocation cannot be adequately grown in place up to `size`, the
363 /// size returned is smaller than `size`.
364 ///
365 /// Note:
366 ///
367 /// * the size value returned can be larger than the size requested during
368 /// allocation
369 /// * when shrinking an allocation, use the size returned to determine
370 /// whether the allocation was shrunk sufficiently or not.
371 ///
372 /// # Safety
373 ///
374 /// The behavior is _undefined_ if:
375 ///
376 /// * `size == 0`, or
377 /// * `size + extra > size_t::max_value()`, or
378 /// * `ptr` does not match a pointer earlier returned by the memory
379 /// allocation functions of this crate, or
380 /// * the memory region referenced by `ptr` has been deallocated.
381 #[cfg_attr(prefixed, link_name = "_rjem_xallocx")]
382 pub fn xallocx(ptr: *mut c_void, size: size_t, extra: size_t, flags: c_int) -> size_t;
383
384 /// Returns the real size of the previously-allocated memory region
385 /// referenced by `ptr`.
386 ///
387 /// The value may be larger than the size requested on allocation.
388 ///
389 /// # Safety
390 ///
391 /// The behavior is _undefined_ if:
392 ///
393 /// * `ptr` does not match a pointer earlier returned by the memory
394 /// allocation functions of this crate, or
395 /// * the memory region referenced by `ptr` has been deallocated.
396 #[cfg_attr(prefixed, link_name = "_rjem_sallocx")]
397 pub fn sallocx(ptr: *const c_void, flags: c_int) -> size_t;
398
399 /// Deallocates previously-allocated memory region referenced by `ptr`.
400 ///
401 /// This makes the space available for future allocations.
402 ///
403 /// # Safety
404 ///
405 /// The behavior is _undefined_ if:
406 ///
407 /// * `ptr` does not match a pointer earlier returned by the memory
408 /// allocation functions of this crate, or
409 /// * `ptr` is null, or
410 /// * the memory region referenced by `ptr` has been deallocated.
411 #[cfg_attr(prefixed, link_name = "_rjem_dallocx")]
412 pub fn dallocx(ptr: *mut c_void, flags: c_int);
413
414 /// Deallocates previously-allocated memory region referenced by `ptr` with
415 /// `size` hint.
416 ///
417 /// This makes the space available for future allocations.
418 ///
419 /// # Safety
420 ///
421 /// The behavior is _undefined_ if:
422 ///
423 /// * `size` is not in range `[req_size, alloc_size]`, where `req_size` is
424 /// the size requested when performing the allocation, and `alloc_size` is
425 /// the allocation size returned by [`nallocx`], [`sallocx`], or
426 /// [`xallocx`],
427 /// * `ptr` does not match a pointer earlier returned by the memory
428 /// allocation functions of this crate, or
429 /// * `ptr` is null, or
430 /// * the memory region referenced by `ptr` has been deallocated.
431 #[cfg_attr(prefixed, link_name = "_rjem_sdallocx")]
432 pub fn sdallocx(ptr: *mut c_void, size: size_t, flags: c_int);
433
434 /// Returns the real size of the allocation that would result from a
435 /// [`mallocx`] function call with the same arguments.
436 ///
437 /// # Errors
438 ///
439 /// If the inputs exceed the maximum supported size class and/or alignment
440 /// it returns zero.
441 ///
442 /// # Safety
443 ///
444 /// The behavior is _undefined_ if `size == 0`.
445 #[cfg_attr(prefixed, link_name = "_rjem_nallocx")]
446 pub fn nallocx(size: size_t, flags: c_int) -> size_t;
447
448 /// Returns the real size of the previously-allocated memory region
449 /// referenced by `ptr`.
450 ///
451 /// The value may be larger than the size requested on allocation.
452 ///
453 /// Although the excess bytes can be overwritten by the application without
454 /// ill effects, this is not good programming practice: the number of excess
455 /// bytes in an allocation depends on the underlying implementation.
456 ///
457 /// The main use of this function is for debugging and introspection.
458 ///
459 /// # Errors
460 ///
461 /// If `ptr` is null, 0 is returned.
462 ///
463 /// # Safety
464 ///
465 /// The behavior is _undefined_ if:
466 ///
467 /// * `ptr` does not match a pointer earlier returned by the memory
468 /// allocation functions of this crate, or
469 /// * the memory region referenced by `ptr` has been deallocated.
470 #[cfg_attr(prefixed, link_name = "_rjem_malloc_usable_size")]
471 pub fn malloc_usable_size(ptr: *const c_void) -> size_t;
472
473 /// General interface for introspecting the memory allocator, as well as
474 /// setting modifiable parameters and triggering actions.
475 ///
476 /// The period-separated name argument specifies a location in a
477 /// tree-structured namespace ([see jemalloc's `MALLCTL`
478 /// documentation][jemalloc_mallctl]).
479 ///
480 /// To read a value, pass a pointer via `oldp` to adequate space to contain
481 /// the value, and a pointer to its length via `oldlenp``; otherwise pass
482 /// null and null. Similarly, to write a value, pass a pointer to the value
483 /// via `newp`, and its length via `newlen`; otherwise pass null and 0.
484 ///
485 /// # Errors
486 ///
487 /// Returns `0` on success, otherwise returns:
488 ///
489 /// * `EINVAL`: if `newp` is not null, and `newlen` is too large or too
490 /// small. Alternatively, `*oldlenp` is too large or too small; in this case
491 /// as much data as possible are read despite the error.
492 ///
493 /// * `ENOENT`: `name` or mib specifies an unknown/invalid value.
494 ///
495 /// * `EPERM`: Attempt to read or write void value, or attempt to write read-only value.
496 ///
497 /// * `EAGAIN`: A memory allocation failure occurred.
498 ///
499 /// * `EFAULT`: An interface with side effects failed in some way not
500 /// directly related to `mallctl` read/write processing.
501 ///
502 /// [jemalloc_mallctl]: http://jemalloc.net/jemalloc.3.html#mallctl_namespace
503 #[cfg_attr(prefixed, link_name = "_rjem_mallctl")]
504 pub fn mallctl(
505 name: *const c_char,
506 oldp: *mut c_void,
507 oldlenp: *mut size_t,
508 newp: *mut c_void,
509 newlen: size_t,
510 ) -> c_int;
511 /// Translates a name to a “Management Information Base” (MIB) that can be
512 /// passed repeatedly to [`mallctlbymib`].
513 ///
514 /// This avoids repeated name lookups for applications that repeatedly query
515 /// the same portion of the namespace.
516 ///
517 /// On success, `mibp` contains an array of `*miblenp` integers, where
518 /// `*miblenp` is the lesser of the number of components in name and the
519 /// input value of `*miblenp`. Thus it is possible to pass a `*miblenp` that is
520 /// smaller than the number of period-separated name components, which
521 /// results in a partial MIB that can be used as the basis for constructing
522 /// a complete MIB. For name components that are integers (e.g. the 2 in
523 /// arenas.bin.2.size), the corresponding MIB component will always be that
524 /// integer.
525 #[cfg_attr(prefixed, link_name = "_rjem_mallctlnametomib")]
526 pub fn mallctlnametomib(name: *const c_char, mibp: *mut size_t, miblenp: *mut size_t) -> c_int;
527
528 /// Like [`mallctl`] but taking a `mib` as input instead of a name.
529 #[cfg_attr(prefixed, link_name = "_rjem_mallctlbymib")]
530 pub fn mallctlbymib(
531 mib: *const size_t,
532 miblen: size_t,
533 oldp: *mut c_void,
534 oldpenp: *mut size_t,
535 newp: *mut c_void,
536 newlen: size_t,
537 ) -> c_int;
538
539 /// Writes summary statistics via the `write_cb` callback function pointer
540 /// and `cbopaque` data passed to `write_cb`, or [`malloc_message`] if `write_cb`
541 /// is null.
542 ///
543 /// The statistics are presented in human-readable form unless “J”
544 /// is specified as a character within the opts string, in which case the
545 /// statistics are presented in JSON format.
546 ///
547 /// This function can be called repeatedly.
548 ///
549 /// General information that never changes during execution can be omitted
550 /// by specifying `g` as a character within the opts string.
551 ///
552 /// Note that [`malloc_message`] uses the `mallctl*` functions internally,
553 /// so inconsistent statistics can be reported if multiple threads use these
554 /// functions simultaneously.
555 ///
556 /// If the Cargo feature `stats` is enabled, `m`, `d`, and `a` can be
557 /// specified to omit merged arena, destroyed merged arena, and per arena
558 /// statistics, respectively; `b` and `l` can be specified to omit per size
559 /// class statistics for bins and large objects, respectively; `x` can be
560 /// specified to omit all mutex statistics. Unrecognized characters are
561 /// silently ignored.
562 ///
563 /// Note that thread caching may prevent some statistics from being
564 /// completely up to date, since extra locking would be required to merge
565 /// counters that track thread cache operations.
566 #[cfg_attr(prefixed, link_name = "_rjem_malloc_stats_print")]
567 pub fn malloc_stats_print(
568 write_cb: Option<unsafe extern "C" fn(*mut c_void, *const c_char)>,
569 cbopaque: *mut c_void,
570 opts: *const c_char,
571 );
572
573 /// Allows overriding the function which emits the text strings forming the
574 /// errors and warnings if for some reason the `STDERR_FILENO` file descriptor
575 /// is not suitable for this.
576 ///
577 /// [`malloc_message`] takes the `cbopaque` pointer argument that is null,
578 /// unless overridden by the arguments in a call to [`malloc_stats_print`],
579 /// followed by a string pointer.
580 ///
581 /// Please note that doing anything which tries to allocate memory in this
582 /// function is likely to result in a crash or deadlock.
583 #[cfg_attr(prefixed, link_name = "_rjem_malloc_message")]
584 pub static mut malloc_message:
585 Option<unsafe extern "C" fn(cbopaque: *mut c_void, s: *const c_char)>;
586
587 /// Compile-time string of configuration options.
588 ///
589 /// Once, when the first call is made to one of the memory allocation
590 /// routines, the allocator initializes its internals based in part on
591 /// various options that can be specified at compile- or run-time.
592 ///
593 /// The string specified via `--with-malloc-conf`, the string pointed to by
594 /// the global variable `malloc_conf`, the “name” of the file referenced by
595 /// the symbolic link named `/etc/malloc.conf`, and the value of the
596 /// environment variable `MALLOC_CONF`, will be interpreted, in that order,
597 /// from left to right as options. Note that `malloc_conf` may be read
598 /// before `main()` is entered, so the declaration of `malloc_conf` should
599 /// specify an initializer that contains the final value to be read by
600 /// `jemalloc`.
601 ///
602 /// `--with-malloc-conf` and `malloc_conf` are compile-time mechanisms, whereas
603 /// `/etc/malloc.conf` and `MALLOC_CONF` can be safely set any time prior to
604 /// program invocation.
605 ///
606 /// An options string is a comma-separated list of `option:value` pairs.
607 /// There is one key corresponding to each `opt.* mallctl` (see the `MALLCTL
608 /// NAMESPACE` section for options documentation). For example,
609 /// `abort:true,narenas:1` sets the `opt.abort` and `opt.narenas` options.
610 /// Some options have boolean values (`true`/`false`), others have integer
611 /// values (base `8`, `10`, or `16`, depending on prefix), and yet others
612 /// have raw string values.
613 #[cfg_attr(prefixed, link_name = "_rjem_malloc_conf")]
614 pub static malloc_conf: Option<&'static c_char>;
615}
616
617/// Extent lifetime management functions.
618pub type extent_hooks_t = extent_hooks_s;
619
620// note: there are two structs here, one is used when compiling the crate normally,
621// and the other one is behind the `--cfg jemallocator_docs` flag and used only
622// when generating docs.
623//
624// For the docs we want to use type aliases here, but `ctest` does see through
625// them when generating the code to verify the FFI bindings, and it needs to
626// be able to tell that these are `fn` types so that `Option<fn>` gets lowered
627// to C function pointers.
628
629#[repr(C)]
630#[cfg(not(jemallocator_docs))]
631#[derive(Copy, Clone, Default)]
632#[doc(hidden)]
633#[allow(missing_docs)]
634pub struct extent_hooks_s {
635 pub alloc: Option<
636 unsafe extern "C" fn(
637 *mut extent_hooks_t,
638 *mut c_void,
639 size_t,
640 size_t,
641 *mut c_bool,
642 *mut c_bool,
643 c_uint,
644 ) -> *mut c_void,
645 >,
646 pub dalloc: Option<
647 unsafe extern "C" fn(*mut extent_hooks_t, *mut c_void, size_t, c_bool, c_uint) -> c_bool,
648 >,
649 pub destroy:
650 Option<unsafe extern "C" fn(*mut extent_hooks_t, *mut c_void, size_t, c_bool, c_uint)>,
651 pub commit: Option<
652 unsafe extern "C" fn(
653 *mut extent_hooks_t,
654 *mut c_void,
655 size_t,
656 size_t,
657 size_t,
658 c_uint,
659 ) -> c_bool,
660 >,
661 pub decommit: Option<
662 unsafe extern "C" fn(
663 *mut extent_hooks_t,
664 *mut c_void,
665 size_t,
666 size_t,
667 size_t,
668 c_uint,
669 ) -> c_bool,
670 >,
671 pub purge_lazy: Option<
672 unsafe extern "C" fn(
673 *mut extent_hooks_t,
674 *mut c_void,
675 size_t,
676 size_t,
677 size_t,
678 c_uint,
679 ) -> c_bool,
680 >,
681 pub purge_forced: Option<
682 unsafe extern "C" fn(
683 *mut extent_hooks_t,
684 *mut c_void,
685 size_t,
686 size_t,
687 size_t,
688 c_uint,
689 ) -> c_bool,
690 >,
691 pub split: Option<
692 unsafe extern "C" fn(
693 *mut extent_hooks_t,
694 *mut c_void,
695 size_t,
696 size_t,
697 size_t,
698 c_bool,
699 c_uint,
700 ) -> c_bool,
701 >,
702 pub merge: Option<
703 unsafe extern "C" fn(
704 *mut extent_hooks_t,
705 *mut c_void,
706 size_t,
707 *mut c_void,
708 size_t,
709 c_bool,
710 c_uint,
711 ) -> c_bool,
712 >,
713}
714
715/// Extent lifetime management functions.
716///
717/// The extent_hooks_t structure comprises function pointers which are described
718/// individually below. `jemalloc` uses these functions to manage extent lifetime,
719/// which starts off with allocation of mapped committed memory, in the simplest
720/// case followed by deallocation. However, there are performance and platform
721/// reasons to retain extents for later reuse. Cleanup attempts cascade from
722/// deallocation to decommit to forced purging to lazy purging, which gives the
723/// extent management functions opportunities to reject the most permanent
724/// cleanup operations in favor of less permanent (and often less costly)
725/// operations. All operations except allocation can be universally opted out of
726/// by setting the hook pointers to `NULL`, or selectively opted out of by
727/// returning failure. Note that once the extent hook is set, the structure is
728/// accessed directly by the associated arenas, so it must remain valid for the
729/// entire lifetime of the arenas.
730#[repr(C)]
731#[cfg(jemallocator_docs)]
732#[derive(Copy, Clone, Default)]
733pub struct extent_hooks_s {
734 #[allow(missing_docs)]
735 pub alloc: Option<extent_alloc_t>,
736 #[allow(missing_docs)]
737 pub dalloc: Option<extent_dalloc_t>,
738 #[allow(missing_docs)]
739 pub destroy: Option<extent_destroy_t>,
740 #[allow(missing_docs)]
741 pub commit: Option<extent_commit_t>,
742 #[allow(missing_docs)]
743 pub decommit: Option<extent_decommit_t>,
744 #[allow(missing_docs)]
745 pub purge_lazy: Option<extent_purge_t>,
746 #[allow(missing_docs)]
747 pub purge_forced: Option<extent_purge_t>,
748 #[allow(missing_docs)]
749 pub split: Option<extent_split_t>,
750 #[allow(missing_docs)]
751 pub merge: Option<extent_merge_t>,
752}
753
754/// Extent allocation function.
755///
756/// On success returns a pointer to `size` bytes of mapped memory on behalf of
757/// arena `arena_ind` such that the extent's base address is a multiple of
758/// `alignment`, as well as setting `*zero` to indicate whether the extent is
759/// zeroed and `*commit` to indicate whether the extent is committed.
760///
761/// Zeroing is mandatory if `*zero` is `true` upon function entry. Committing is mandatory if
762/// `*commit` is true upon function entry. If `new_addr` is not null, the returned
763/// pointer must be `new_addr` on success or null on error.
764///
765/// Committed memory may be committed in absolute terms as on a system that does
766/// not overcommit, or in implicit terms as on a system that overcommits and
767/// satisfies physical memory needs on demand via soft page faults. Note that
768/// replacing the default extent allocation function makes the arena's
769/// `arena.<i>.dss` setting irrelevant.
770///
771/// # Errors
772///
773/// On error the function returns null and leaves `*zero` and `*commit` unmodified.
774///
775/// # Safety
776///
777/// The behavior is _undefined_ if:
778///
779/// * the `size` parameter is not a multiple of the page size
780/// * the `alignment` parameter is not a power of two at least as large as the page size
781pub type extent_alloc_t = unsafe extern "C" fn(
782 extent_hooks: *mut extent_hooks_t,
783 new_addr: *mut c_void,
784 size: size_t,
785 alignment: size_t,
786 zero: *mut c_bool,
787 commit: *mut c_bool,
788 arena_ind: c_uint,
789) -> *mut c_void;
790
791/// Extent deallocation function.
792///
793/// Deallocates an extent at given `addr` and `size` with `committed`/decommited
794/// memory as indicated, on behalf of arena `arena_ind`, returning `false` upon
795/// success.
796///
797/// If the function returns `true`, this indicates opt-out from deallocation;
798/// the virtual memory mapping associated with the extent remains mapped, in the
799/// same commit state, and available for future use, in which case it will be
800/// automatically retained for later reuse.
801pub type extent_dalloc_t = unsafe extern "C" fn(
802 extent_hooks: *mut extent_hooks_t,
803 addr: *mut c_void,
804 size: size_t,
805 committed: c_bool,
806 arena_ind: c_uint,
807) -> c_bool;
808
809/// Extent destruction function.
810///
811/// Unconditionally destroys an extent at given `addr` and `size` with
812/// `committed`/decommited memory as indicated, on behalf of arena `arena_ind`.
813///
814/// This function may be called to destroy retained extents during arena
815/// destruction (see `arena.<i>.destroy`).
816pub type extent_destroy_t = unsafe extern "C" fn(
817 extent_hooks: *mut extent_hooks_t,
818 addr: *mut c_void,
819 size: size_t,
820 committed: c_bool,
821 arena_ind: c_uint,
822);
823
824/// Extent commit function.
825///
826/// Commits zeroed physical memory to back pages within an extent at given
827/// `addr` and `size` at `offset` bytes, extending for `length` on behalf of
828/// arena `arena_ind`, returning `false` upon success.
829///
830/// Committed memory may be committed in absolute terms as on a system that does
831/// not overcommit, or in implicit terms as on a system that overcommits and
832/// satisfies physical memory needs on demand via soft page faults. If the
833/// function returns `true`, this indicates insufficient physical memory to
834/// satisfy the request.
835pub type extent_commit_t = unsafe extern "C" fn(
836 extent_hooks: *mut extent_hooks_t,
837 addr: *mut c_void,
838 size: size_t,
839 offset: size_t,
840 length: size_t,
841 arena_ind: c_uint,
842) -> c_bool;
843
844/// Extent decommit function.
845///
846/// Decommits any physical memory that is backing pages within an extent at
847/// given `addr` and `size` at `offset` bytes, extending for `length` on behalf of arena
848/// `arena_ind`, returning `false` upon success, in which case the pages will be
849/// committed via the extent commit function before being reused.
850///
851/// If the function returns `true`, this indicates opt-out from decommit; the
852/// memory remains committed and available for future use, in which case it will
853/// be automatically retained for later reuse.
854pub type extent_decommit_t = unsafe extern "C" fn(
855 extent_hooks: *mut extent_hooks_t,
856 addr: *mut c_void,
857 size: size_t,
858 offset: size_t,
859 length: size_t,
860 arena_ind: c_uint,
861) -> c_bool;
862
863/// Extent purge function.
864///
865/// Discards physical pages within the virtual memory mapping associated with an
866/// extent at given `addr` and `size` at `offset` bytes, extending for `length` on
867/// behalf of arena `arena_ind`.
868///
869/// A lazy extent purge function (e.g. implemented via `madvise(...MADV_FREE)`)
870/// can delay purging indefinitely and leave the pages within the purged virtual
871/// memory range in an indeterminite state, whereas a forced extent purge
872/// function immediately purges, and the pages within the virtual memory range
873/// will be zero-filled the next time they are accessed. If the function returns
874/// `true`, this indicates failure to purge.
875pub type extent_purge_t = unsafe extern "C" fn(
876 extent_hooks: *mut extent_hooks_t,
877 addr: *mut c_void,
878 size: size_t,
879 offset: size_t,
880 length: size_t,
881 arena_ind: c_uint,
882) -> c_bool;
883
884/// Extent split function.
885///
886/// Optionally splits an extent at given `addr` and `size` into two adjacent
887/// extents, the first of `size_a` bytes, and the second of `size_b` bytes,
888/// operating on `committed`/decommitted memory as indicated, on behalf of arena
889/// `arena_ind`, returning `false` upon success.
890///
891/// If the function returns `true`, this indicates that the extent remains
892/// unsplit and therefore should continue to be operated on as a whole.
893pub type extent_split_t = unsafe extern "C" fn(
894 extent_hooks: *mut extent_hooks_t,
895 addr: *mut c_void,
896 size: size_t,
897 size_a: size_t,
898 size_b: size_t,
899 committed: c_bool,
900 arena_ind: c_uint,
901) -> c_bool;
902
903/// Extent merge function.
904///
905/// Optionally merges adjacent extents, at given `addr_a` and `size_a` with given
906/// `addr_b` and `size_b` into one contiguous extent, operating on
907/// `committed`/decommitted memory as indicated, on behalf of arena `arena_ind`,
908/// returning `false` upon success.
909///
910/// If the function returns `true`, this indicates that the extents remain
911/// distinct mappings and therefore should continue to be operated on
912/// independently.
913pub type extent_merge_t = unsafe extern "C" fn(
914 extent_hooks: *mut extent_hooks_t,
915 addr_a: *mut c_void,
916 size_a: size_t,
917 addr_b: *mut c_void,
918 size_b: size_t,
919 committed: c_bool,
920 arena_ind: c_uint,
921) -> c_bool;
922
923#[allow(missing_docs)]
924mod env;
925
926pub use env::*;
927
928// When using the `"override_allocator_on_supported_platforms"` feature flag,
929// the user wants us to globally override the system allocator.
930//
931// However, since we build `jemalloc` as a static library (an archive), the
932// linker may decide to not care about our overrides if it can't directly see
933// references to the symbols, see the following link for details:
934// <https://maskray.me/blog/2021-06-20-symbol-processing#archive-processing>
935//
936// This is problematic if `jemalloc_sys` is used from a library that by itself
937// doesn't allocate, while invoking other shared libraries that do.
938//
939// Another especially problematic case would be something like the following:
940//
941// ```
942// // Call `malloc` whose symbol is looked up statically.
943// let ptr = libc::malloc(42);
944//
945// // But use a dynamically looked up `free`.
946// let free = libc::dlsym(null_mut(), c"free".as_ptr());
947// let free = transmute::<*mut c_void, unsafe extern "C" fn(*mut c_void)>(free);
948// free(ptr);
949// ```
950//
951// Since if the `malloc` and `free` provided by `jemalloc` end up in different
952// object files in the archive (NOTE: In practice, this is unlikely to be an
953// issue, since `jemalloc.c` contains all the implementations and is compiled
954// as a single object file), the linker would think that only `malloc` was
955// used, and would never load the `free` that we also want (and hence we'd end
956// up executing jemalloc's `malloc` and the system's `free`, which is UB).
957//
958// To avoid this problem, we make sure that all the allocator functions are
959// visible to the linker, such that it will always override all of them.
960//
961// We do this by referencing these symbols in `#[used]` statics, which makes
962// them known to `rustc`, which will reference them in a `symbols.o` stub file
963// that is later passed to the linker. See the following link for details on
964// how this works:
965// <https://github.com/rust-lang/rust/pull/95604>
966
967#[cfg(all(
968 feature = "override_allocator_on_supported_platforms",
969 not(target_vendor = "apple")
970))]
971mod set_up_statics {
972 use super::*;
973
974 #[used]
975 static USED_MALLOC: unsafe extern "C" fn(usize) -> *mut c_void = malloc;
976 #[used]
977 static USED_CALLOC: unsafe extern "C" fn(usize, usize) -> *mut c_void = calloc;
978 #[used]
979 static USED_POSIX_MEMALIGN: unsafe extern "C" fn(*mut *mut c_void, usize, usize) -> c_int =
980 posix_memalign;
981 #[used]
982 static USED_ALIGNED_ALLOC: unsafe extern "C" fn(usize, usize) -> *mut c_void = aligned_alloc;
983 #[used]
984 static USED_REALLOC: unsafe extern "C" fn(*mut c_void, usize) -> *mut c_void = realloc;
985 #[used]
986 static USED_FREE: unsafe extern "C" fn(*mut c_void) = free;
987}
988
989// On macOS, jemalloc doesn't directly override malloc/free, but instead
990// registers itself with the allocator's zone APIs in a ctor (`zone_register`
991// is marked with `__attribute__((constructor))`).
992//
993// Similarly to above though, for the Mach-O linker to actually consider ctors
994// as "used" when defined in an archive member in a static library, so we need
995// to explicitly reference the function via. Rust's `#[used]`.
996
997#[cfg(all(
998 feature = "override_allocator_on_supported_platforms",
999 target_vendor = "apple"
1000))]
1001#[used]
1002static USED_ZONE_REGISTER: unsafe extern "C" fn() = {
1003 extern "C" {
1004 #[cfg_attr(prefixed, link_name = "_rjem_je_zone_register")]
1005 #[cfg_attr(not(prefixed), link_name = "je_zone_register")]
1006 fn zone_register();
1007 }
1008 zone_register
1009};