//! Rust bindings to the `jemalloc` C library. //! //! `jemalloc` is a general purpose memory allocation, its documentation //! can be found here: //! //! * [API documentation][jemalloc_docs] //! * [Wiki][jemalloc_wiki] (design documents, presentations, profiling, debugging, tuning, ...) //! //! `jemalloc` exposes both a standard and a non-standard API. //! //! # Standard API //! //! The standard API includes: the [`malloc`], [`calloc`], [`realloc`], and //! [`free`], which conform to to ISO/IEC 9899:1990 (“ISO C90”), //! [`posix_memalign`] which conforms to conforms to POSIX.1-2016, and //! [`aligned_alloc`]. //! //! Note that these standard leave some details as _implementation defined_. //! This docs document this behavior for `jemalloc`, but keep in mind that other //! standard-conforming implementations of these functions in other allocators //! might behave slightly different. //! //! # Non-Standard API //! //! The non-standard API includes: [`mallocx`], [`rallocx`], [`xallocx`], //! [`sallocx`], [`dallocx`], [`sdallocx`], and [`nallocx`]. These functions all //! have a `flags` argument that can be used to specify options. Use bitwise or //! `|` to specify one or more of the following: [`MALLOCX_LG_ALIGN`], //! [`MALLOCX_ALIGN`], [`MALLOCX_ZERO`], [`MALLOCX_TCACHE`], //! [`MALLOCX_TCACHE_NONE`], and [`MALLOCX_ARENA`]. //! //! # Environment variables //! //! The `MALLOC_CONF` environment variable affects the execution of the allocation functions. //! //! For the documentation of the [`MALLCTL` namespace visit the jemalloc //! documenation][jemalloc_mallctl]. //! //! [jemalloc_docs]: http://jemalloc.net/jemalloc.3.html //! [jemalloc_wiki]: https://github.com/jemalloc/jemalloc/wiki //! [jemalloc_mallctl]: http://jemalloc.net/jemalloc.3.html#mallctl_namespace #![no_std] #![allow(non_snake_case, non_camel_case_types)] #![cfg_attr( feature = "cargo-clippy", allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap) )] // TODO: rename the following lint on next minor bump #![allow(renamed_and_removed_lints)] #![deny(missing_docs, broken_intra_doc_links)] use libc::{c_char, c_int, c_uint, c_void, size_t}; // jemalloc uses `stdbool.h` to define `bool` for which the Rust equivalent is `bool`. // However jemalloc also has its own `stdbool.h` that it uses when compiling with MSVC, // and this header defines `bool` as `BOOL` which in turn is `int`. #[cfg(target_env = "msvc")] type c_bool = c_int; #[cfg(not(target_env = "msvc"))] type c_bool = bool; /// Align the memory allocation to start at an address that is a /// multiple of `1 << la`. /// /// # Safety /// /// It does not validate that `la` is within the valid range. #[inline] pub const fn MALLOCX_LG_ALIGN(la: usize) -> c_int { la as c_int } /// Align the memory allocation to start at an address that is a multiple of `align`, /// where a is a power of two. /// /// # Safety /// /// This macro does not validate that a is a power of 2. #[inline] pub const fn MALLOCX_ALIGN(aling: usize) -> c_int { aling.trailing_zeros() as c_int } /// Initialize newly allocated memory to contain zero bytes. /// /// In the growing reallocation case, the real size prior to reallocation /// defines the boundary between untouched bytes and those that are initialized /// to contain zero bytes. /// /// If this option is not set, newly allocated memory is uninitialized. pub const MALLOCX_ZERO: c_int = 0x40; /// Use the thread-specific cache (_tcache_) specified by the identifier `tc`. /// /// # Safety /// /// `tc` must have been acquired via the `tcache.create mallctl`. This function /// does not validate that `tc` specifies a valid identifier. #[inline] pub const fn MALLOCX_TCACHE(tc: usize) -> c_int { tc.wrapping_add(2).wrapping_shl(8) as c_int } /// Do not use a thread-specific cache (_tcache_). /// /// Unless `MALLOCX_TCACHE(tc)` or `MALLOCX_TCACHE_NONE` is specified, an /// automatically managed _tcache_ will be used under many circumstances. /// /// # Safety /// /// This option cannot be used in the same `flags` argument as /// `MALLOCX_TCACHE(tc)`. // FIXME: This should just be a const. pub const MALLOCX_TCACHE_NONE: c_int = MALLOCX_TCACHE((-1isize) as usize); /// Use the arena specified by the index `a`. /// /// This option has no effect for regions that were allocated via an arena other /// than the one specified. /// /// # Safety /// /// This function does not validate that `a` specifies an arena index in the /// valid range. #[inline] pub const fn MALLOCX_ARENA(a: usize) -> c_int { (a as c_int).wrapping_add(1).wrapping_shl(20) } extern "C" { /// Allocates `size` bytes of uninitialized memory. /// /// It returns a pointer to the start (lowest byte address) of the allocated /// space. This pointer is suitably aligned so that it may be assigned to a /// pointer to any type of object and then used to access such an object in /// the space allocated until the space is explicitly deallocated. Each /// yielded pointer points to an object disjoint from any other object. /// /// If the `size` of the space requested is zero, either a null pointer is /// returned, or the behavior is as if the `size` were some nonzero value, /// except that the returned pointer shall not be used to access an object. /// /// # Errors /// /// If the space cannot be allocated, a null pointer is returned and `errno` /// is set to `ENOMEM`. #[cfg_attr(prefixed, link_name = "je_malloc")] pub fn malloc(size: size_t) -> *mut c_void; /// Allocates zero-initialized space for an array of `number` objects, each /// of whose size is `size`. /// /// The result is identical to calling [`malloc`] with an argument of /// `number * size`, with the exception that the allocated memory is /// explicitly initialized to _zero_ bytes. /// /// Note: zero-initialized memory need not be the same as the /// representation of floating-point zero or a null pointer constant. #[cfg_attr(prefixed, link_name = "je_calloc")] pub fn calloc(number: size_t, size: size_t) -> *mut c_void; /// Allocates `size` bytes of memory at an address which is a multiple of /// `alignment` and is placed in `*ptr`. /// /// If `size` is zero, then the value placed in `*ptr` is either null, or /// the behavior is as if the `size` were some nonzero value, except that /// the returned pointer shall not be used to access an object. /// /// # Errors /// /// On success, it returns zero. On error, the value of `errno` is _not_ set, /// `*ptr` is not modified, and the return values can be: /// /// - `EINVAL`: the `alignment` argument was not a power-of-two or was not a multiple of /// `mem::size_of::<*const c_void>()`. /// - `ENOMEM`: there was insufficient memory to fulfill the allocation request. /// /// # Safety /// /// The behavior is _undefined_ if: /// /// * `ptr` is null. #[cfg_attr(prefixed, link_name = "je_posix_memalign")] pub fn posix_memalign(ptr: *mut *mut c_void, alignment: size_t, size: size_t) -> c_int; /// Allocates `size` bytes of memory at an address which is a multiple of /// `alignment`. /// /// If the `size` of the space requested is zero, either a null pointer is /// returned, or the behavior is as if the `size` were some nonzero value, /// except that the returned pointer shall not be used to access an object. /// /// # Errors /// /// Returns null if the request fails. /// /// # Safety /// /// The behavior is _undefined_ if: /// /// * `alignment` is not a power-of-two /// * `size` is not an integral multiple of `alignment` #[cfg_attr(prefixed, link_name = "je_aligned_alloc")] pub fn aligned_alloc(alignment: size_t, size: size_t) -> *mut c_void; /// Resizes the previously-allocated memory region referenced by `ptr` to /// `size` bytes. /// /// Deallocates the old object pointed to by `ptr` and returns a pointer to /// a new object that has the size specified by `size`. The contents of the /// new object are the same as that of the old object prior to deallocation, /// up to the lesser of the new and old sizes. /// /// The memory in the new object beyond the size of the old object is /// uninitialized. /// /// The returned pointer to a new object may have the same value as a /// pointer to the old object, but [`realloc`] may move the memory /// allocation, resulting in a different return value than `ptr`. /// /// If `ptr` is null, [`realloc`] behaves identically to [`malloc`] for the /// specified size. /// /// If the size of the space requested is zero, the behavior is /// implementation-defined: either a null pointer is returned, or the /// behavior is as if the size were some nonzero value, except that the /// returned pointer shall not be used to access an object # Errors /// /// # Errors /// /// If memory for the new object cannot be allocated, the old object is not /// deallocated, its value is unchanged, [`realloc`] returns null, and /// `errno` is set to `ENOMEM`. /// /// # Safety /// /// The behavior is _undefined_ if: /// /// * `ptr` does not match a pointer previously returned by the memory /// allocation functions of this crate, or /// * the memory region referenced by `ptr` has been deallocated. #[cfg_attr(prefixed, link_name = "je_realloc")] pub fn realloc(ptr: *mut c_void, size: size_t) -> *mut c_void; /// Deallocates previously-allocated memory region referenced by `ptr`. /// /// This makes the space available for future allocations. /// /// If `ptr` is null, no action occurs. /// /// # Safety /// /// The behavior is _undefined_ if: /// /// * `ptr` does not match a pointer earlier returned by the memory /// allocation functions of this crate, or /// * the memory region referenced by `ptr` has been deallocated. #[cfg_attr(prefixed, link_name = "je_free")] pub fn free(ptr: *mut c_void); /// Allocates at least `size` bytes of memory according to `flags`. /// /// It returns a pointer to the start (lowest byte address) of the allocated /// space. This pointer is suitably aligned so that it may be assigned to a /// pointer to any type of object and then used to access such an object in /// the space allocated until the space is explicitly deallocated. Each /// yielded pointer points to an object disjoint from any other object. /// /// # Errors /// /// On success it returns a non-null pointer. A null pointer return value /// indicates that insufficient contiguous memory was available to service /// the allocation request. /// /// # Safety /// /// The behavior is _undefined_ if `size == 0`. #[cfg_attr(prefixed, link_name = "je_mallocx")] pub fn mallocx(size: size_t, flags: c_int) -> *mut c_void; /// Resizes the previously-allocated memory region referenced by `ptr` to be /// at least `size` bytes. /// /// Deallocates the old object pointed to by `ptr` and returns a pointer to /// a new object that has the size specified by `size`. The contents of the /// new object are the same as that of the old object prior to deallocation, /// up to the lesser of the new and old sizes. /// /// The the memory in the new object beyond the size of the old object is /// obtained according to `flags` (it might be uninitialized). /// /// The returned pointer to a new object may have the same value as a /// pointer to the old object, but [`rallocx`] may move the memory /// allocation, resulting in a different return value than `ptr`. /// /// # Errors /// /// On success it returns a non-null pointer. A null pointer return value /// indicates that insufficient contiguous memory was available to service /// the allocation request. In this case, the old object is not /// deallocated, and its value is unchanged. /// /// # Safety /// /// The behavior is _undefiend_ if: /// /// * `size == 0`, or /// * `ptr` does not match a pointer earlier returned by /// the memory allocation functions of this crate, or /// * the memory region referenced by `ptr` has been deallocated. #[cfg_attr(prefixed, link_name = "je_rallocx")] pub fn rallocx(ptr: *mut c_void, size: size_t, flags: c_int) -> *mut c_void; /// Resizes the previously-allocated memory region referenced by `ptr` _in /// place_ to be at least `size` bytes, returning the real size of the /// allocation. /// /// Deallocates the old object pointed to by `ptr` and sets `ptr` to a new /// object that has the size returned; the old a new objects share the same /// base address. The contents of the new object are the same as that of the /// old object prior to deallocation, up to the lesser of the new and old /// sizes. /// /// If `extra` is non-zero, an attempt is made to resize the allocation to /// be at least `size + extra` bytes. Inability to allocate the `extra` /// bytes will not by itself result in failure to resize. /// /// The memory in the new object beyond the size of the old object is /// obtained according to `flags` (it might be uninitialized). /// /// # Errors /// /// If the allocation cannot be adequately grown in place up to `size`, the /// size returned is smaller than `size`. /// /// Note: /// /// * the size value returned can be larger than the size requested during /// allocation /// * when shrinking an allocation, use the size returned to determine /// whether the allocation was shrunk sufficiently or not. /// /// # Safety /// /// The behavior is _undefined_ if: /// /// * `size == 0`, or /// * `size + extra > size_t::max_value()`, or /// * `ptr` does not match a pointer earlier returned by the memory /// allocation functions of this crate, or /// * the memory region referenced by `ptr` has been deallocated. #[cfg_attr(prefixed, link_name = "je_xallocx")] pub fn xallocx(ptr: *mut c_void, size: size_t, extra: size_t, flags: c_int) -> size_t; /// Returns the real size of the previously-allocated memory region /// referenced by `ptr`. /// /// The value may be larger than the size requested on allocation. /// /// # Safety /// /// The behavior is _undefined_ if: /// /// * `ptr` does not match a pointer earlier returned by the memory /// allocation functions of this crate, or /// * the memory region referenced by `ptr` has been deallocated. #[cfg_attr(prefixed, link_name = "je_sallocx")] pub fn sallocx(ptr: *const c_void, flags: c_int) -> size_t; /// Deallocates previously-allocated memory region referenced by `ptr`. /// /// This makes the space available for future allocations. /// /// # Safety /// /// The behavior is _undefined_ if: /// /// * `ptr` does not match a pointer earlier returned by the memory /// allocation functions of this crate, or /// * `ptr` is null, or /// * the memory region referenced by `ptr` has been deallocated. #[cfg_attr(prefixed, link_name = "je_dallocx")] pub fn dallocx(ptr: *mut c_void, flags: c_int); /// Deallocates previously-allocated memory region referenced by `ptr` with /// `size` hint. /// /// This makes the space available for future allocations. /// /// # Safety /// /// The behavior is _undefined_ if: /// /// * `size` is not in range `[req_size, alloc_size]`, where `req_size` is /// the size requested when performing the allocation, and `alloc_size` is /// the allocation size returned by [`nallocx`], [`sallocx`], or /// [`xallocx`], /// * `ptr` does not match a pointer earlier returned by the memory /// allocation functions of this crate, or /// * `ptr` is null, or /// * the memory region referenced by `ptr` has been deallocated. #[cfg_attr(prefixed, link_name = "je_sdallocx")] pub fn sdallocx(ptr: *mut c_void, size: size_t, flags: c_int); /// Returns the real size of the allocation that would result from a /// [`mallocx`] function call with the same arguments. /// /// # Errors /// /// If the inputs exceed the maximum supported size class and/or alignment /// it returns zero. /// /// # Safety /// /// The behavior is _undefined_ if `size == 0`. #[cfg_attr(prefixed, link_name = "je_nallocx")] pub fn nallocx(size: size_t, flags: c_int) -> size_t; /// Returns the real size of the previously-allocated memory region /// referenced by `ptr`. /// /// The value may be larger than the size requested on allocation. /// /// Although the excess bytes can be overwritten by the application without /// ill effects, this is not good programming practice: the number of excess /// bytes in an allocation depends on the underlying implementation. /// /// The main use of this function is for debugging and introspection. /// /// # Errors /// /// If `ptr` is null, 0 is returned. /// /// # Safety /// /// The behavior is _undefined_ if: /// /// * `ptr` does not match a pointer earlier returned by the memory /// allocation functions of this crate, or /// * the memory region referenced by `ptr` has been deallocated. #[cfg_attr(prefixed, link_name = "je_malloc_usable_size")] pub fn malloc_usable_size(ptr: *const c_void) -> size_t; /// General interface for introspecting the memory allocator, as well as /// setting modifiable parameters and triggering actions. /// /// The period-separated name argument specifies a location in a /// tree-structured namespace ([see jemalloc's `MALLCTL` /// documentation][jemalloc_mallctl]). /// /// To read a value, pass a pointer via `oldp` to adequate space to contain /// the value, and a pointer to its length via `oldlenp``; otherwise pass /// null and null. Similarly, to write a value, pass a pointer to the value /// via `newp`, and its length via `newlen`; otherwise pass null and 0. /// /// # Errors /// /// Returns `0` on success, otherwise returns: /// /// * `EINVAL`: if `newp` is not null, and `newlen` is too large or too /// small. Alternatively, `*oldlenp` is too large or too small; in this case /// as much data as possible are read despite the error. /// /// * `ENOENT`: `name` or mib specifies an unknown/invalid value. /// /// * `EPERM`: Attempt to read or write void value, or attempt to write read-only value. /// /// * `EAGAIN`: A memory allocation failure occurred. /// /// * `EFAULT`: An interface with side effects failed in some way not /// directly related to `mallctl` read/write processing. /// /// [jemalloc_mallctl]: http://jemalloc.net/jemalloc.3.html#mallctl_namespace #[cfg_attr(prefixed, link_name = "je_mallctl")] pub fn mallctl( name: *const c_char, oldp: *mut c_void, oldlenp: *mut size_t, newp: *mut c_void, newlen: size_t, ) -> c_int; /// Translates a name to a “Management Information Base” (MIB) that can be /// passed repeatedly to [`mallctlbymib`]. /// /// This avoids repeated name lookups for applications that repeatedly query /// the same portion of the namespace. /// /// On success, `mibp` contains an array of `*miblenp` integers, where /// `*miblenp` is the lesser of the number of components in name and the /// input value of `*miblenp`. Thus it is possible to pass a `*miblenp` that is /// smaller than the number of period-separated name components, which /// results in a partial MIB that can be used as the basis for constructing /// a complete MIB. For name components that are integers (e.g. the 2 in /// arenas.bin.2.size), the corresponding MIB component will always be that /// integer. #[cfg_attr(prefixed, link_name = "je_mallctlnametomib")] pub fn mallctlnametomib(name: *const c_char, mibp: *mut size_t, miblenp: *mut size_t) -> c_int; /// Like [`mallctl`] but taking a `mib` as input instead of a name. #[cfg_attr(prefixed, link_name = "je_mallctlbymib")] pub fn mallctlbymib( mib: *const size_t, miblen: size_t, oldp: *mut c_void, oldpenp: *mut size_t, newp: *mut c_void, newlen: size_t, ) -> c_int; /// Writes summary statistics via the `write_cb` callback function pointer /// and `cbopaque` data passed to `write_cb`, or [`malloc_message`] if `write_cb` /// is null. /// /// The statistics are presented in human-readable form unless “J” /// is specified as a character within the opts string, in which case the /// statistics are presented in JSON format. /// /// This function can be called repeatedly. /// /// General information that never changes during execution can be omitted /// by specifying `g` as a character within the opts string. /// /// Note that [`malloc_message`] uses the `mallctl*` functions internally, /// so inconsistent statistics can be reported if multiple threads use these /// functions simultaneously. /// /// If the Cargo feature `stats` is enabled, `m`, `d`, and `a` can be /// specified to omit merged arena, destroyed merged arena, and per arena /// statistics, respectively; `b` and `l` can be specified to omit per size /// class statistics for bins and large objects, respectively; `x` can be /// specified to omit all mutex statistics. Unrecognized characters are /// silently ignored. /// /// Note that thread caching may prevent some statistics from being /// completely up to date, since extra locking would be required to merge /// counters that track thread cache operations. #[cfg_attr(prefixed, link_name = "je_malloc_stats_print")] pub fn malloc_stats_print( write_cb: Option, cbopaque: *mut c_void, opts: *const c_char, ); /// Allows overriding the function which emits the text strings forming the /// errors and warnings if for some reason the `STDERR_FILENO` file descriptor /// is not suitable for this. /// /// [`malloc_message`] takes the `cbopaque` pointer argument that is null, /// unless overridden by the arguments in a call to [`malloc_stats_print`], /// followed by a string pointer. /// /// Please note that doing anything which tries to allocate memory in this /// function is likely to result in a crash or deadlock. #[cfg_attr(prefixed, link_name = "je_malloc_message")] pub static mut malloc_message: Option; /// Compile-time string of configuration options. /// /// Once, when the first call is made to one of the memory allocation /// routines, the allocator initializes its internals based in part on /// various options that can be specified at compile- or run-time. /// /// The string specified via `--with-malloc-conf`, the string pointed to by /// the global variable `malloc_conf`, the “name” of the file referenced by /// the symbolic link named `/etc/malloc.conf`, and the value of the /// environment variable `MALLOC_CONF`, will be interpreted, in that order, /// from left to right as options. Note that `malloc_conf` may be read /// before `main()` is entered, so the declaration of `malloc_conf` should /// specify an initializer that contains the final value to be read by /// `jemalloc`. /// /// `--with-malloc-conf` and `malloc_conf` are compile-time mechanisms, whereas /// `/etc/malloc.conf` and `MALLOC_CONF` can be safely set any time prior to /// program invocation. /// /// An options string is a comma-separated list of `option:value` pairs. /// There is one key corresponding to each `opt.* mallctl` (see the `MALLCTL /// NAMESPACE` section for options documentation). For example, /// `abort:true,narenas:1` sets the `opt.abort` and `opt.narenas` options. /// Some options have boolean values (`true`/`false`), others have integer /// values (base `8`, `10`, or `16`, depending on prefix), and yet others /// have raw string values. #[cfg_attr(prefixed, link_name = "je_malloc_conf")] pub static malloc_conf: Option<&'static c_char>; } /// Extent lifetime management functions. pub type extent_hooks_t = extent_hooks_s; // note: there are two structs here, one is used when compiling the crate normally, // and the other one is behind the `--cfg jemallocator_docs` flag and used only // when generating docs. // // For the docs we want to use type aliases here, but `ctest` does see through // them when generating the code to verify the FFI bindings, and it needs to // be able to tell that these are `fn` types so that `Option` gets lowered // to C function pointers. #[repr(C)] #[cfg(not(jemallocator_docs))] #[derive(Copy, Clone, Default)] #[doc(hidden)] #[allow(missing_docs)] pub struct extent_hooks_s { pub alloc: Option< unsafe extern "C" fn( *mut extent_hooks_t, *mut c_void, size_t, size_t, *mut c_bool, *mut c_bool, c_uint, ) -> *mut c_void, >, pub dalloc: Option< unsafe extern "C" fn(*mut extent_hooks_t, *mut c_void, size_t, c_bool, c_uint) -> c_bool, >, pub destroy: Option, pub commit: Option< unsafe extern "C" fn( *mut extent_hooks_t, *mut c_void, size_t, size_t, size_t, c_uint, ) -> c_bool, >, pub decommit: Option< unsafe extern "C" fn( *mut extent_hooks_t, *mut c_void, size_t, size_t, size_t, c_uint, ) -> c_bool, >, pub purge_lazy: Option< unsafe extern "C" fn( *mut extent_hooks_t, *mut c_void, size_t, size_t, size_t, c_uint, ) -> c_bool, >, pub purge_forced: Option< unsafe extern "C" fn( *mut extent_hooks_t, *mut c_void, size_t, size_t, size_t, c_uint, ) -> c_bool, >, pub split: Option< unsafe extern "C" fn( *mut extent_hooks_t, *mut c_void, size_t, size_t, size_t, c_bool, c_uint, ) -> c_bool, >, pub merge: Option< unsafe extern "C" fn( *mut extent_hooks_t, *mut c_void, size_t, *mut c_void, size_t, c_bool, c_uint, ) -> c_bool, >, } /// Extent lifetime management functions. /// /// The extent_hooks_t structure comprises function pointers which are described /// individually below. `jemalloc` uses these functions to manage extent lifetime, /// which starts off with allocation of mapped committed memory, in the simplest /// case followed by deallocation. However, there are performance and platform /// reasons to retain extents for later reuse. Cleanup attempts cascade from /// deallocation to decommit to forced purging to lazy purging, which gives the /// extent management functions opportunities to reject the most permanent /// cleanup operations in favor of less permanent (and often less costly) /// operations. All operations except allocation can be universally opted out of /// by setting the hook pointers to `NULL`, or selectively opted out of by /// returning failure. Note that once the extent hook is set, the structure is /// accessed directly by the associated arenas, so it must remain valid for the /// entire lifetime of the arenas. #[repr(C)] #[cfg(jemallocator_docs)] #[derive(Copy, Clone, Default)] pub struct extent_hooks_s { #[allow(missing_docs)] pub alloc: Option, #[allow(missing_docs)] pub dalloc: Option, #[allow(missing_docs)] pub destroy: Option, #[allow(missing_docs)] pub commit: Option, #[allow(missing_docs)] pub decommit: Option, #[allow(missing_docs)] pub purge_lazy: Option, #[allow(missing_docs)] pub purge_forced: Option, #[allow(missing_docs)] pub split: Option, #[allow(missing_docs)] pub merge: Option, } /// Extent allocation function. /// /// On success returns a pointer to `size` bytes of mapped memory on behalf of /// arena `arena_ind` such that the extent's base address is a multiple of /// `alignment`, as well as setting `*zero` to indicate whether the extent is /// zeroed and `*commit` to indicate whether the extent is committed. /// /// Zeroing is mandatory if `*zero` is `true` upon function entry. Committing is mandatory if /// `*commit` is true upon function entry. If `new_addr` is not null, the returned /// pointer must be `new_addr` on success or null on error. /// /// Committed memory may be committed in absolute terms as on a system that does /// not overcommit, or in implicit terms as on a system that overcommits and /// satisfies physical memory needs on demand via soft page faults. Note that /// replacing the default extent allocation function makes the arena's /// `arena..dss` setting irrelevant. /// /// # Errors /// /// On error the function returns null and leaves `*zero` and `*commit` unmodified. /// /// # Safety /// /// The behavior is _undefined_ if: /// /// * the `size` parameter is not a multiple of the page size /// * the `alignment` parameter is not a power of two at least as large as the page size pub type extent_alloc_t = unsafe extern "C" fn( extent_hooks: *mut extent_hooks_t, new_addr: *mut c_void, size: size_t, alignment: size_t, zero: *mut c_bool, commit: *mut c_bool, arena_ind: c_uint, ) -> *mut c_void; /// Extent deallocation function. /// /// Deallocates an extent at given `addr` and `size` with `committed`/decommited /// memory as indicated, on behalf of arena `arena_ind`, returning `false` upon /// success. /// /// If the function returns `true`, this indicates opt-out from deallocation; /// the virtual memory mapping associated with the extent remains mapped, in the /// same commit state, and available for future use, in which case it will be /// automatically retained for later reuse. pub type extent_dalloc_t = unsafe extern "C" fn( extent_hooks: *mut extent_hooks_t, addr: *mut c_void, size: size_t, committed: c_bool, arena_ind: c_uint, ) -> c_bool; /// Extent destruction function. /// /// Unconditionally destroys an extent at given `addr` and `size` with /// `committed`/decommited memory as indicated, on behalf of arena `arena_ind`. /// /// This function may be called to destroy retained extents during arena /// destruction (see `arena..destroy`). pub type extent_destroy_t = unsafe extern "C" fn( extent_hooks: *mut extent_hooks_t, addr: *mut c_void, size: size_t, committed: c_bool, arena_ind: c_uint, ); /// Extent commit function. /// /// Commits zeroed physical memory to back pages within an extent at given /// `addr` and `size` at `offset` bytes, extending for `length` on behalf of /// arena `arena_ind`, returning `false` upon success. /// /// Committed memory may be committed in absolute terms as on a system that does /// not overcommit, or in implicit terms as on a system that overcommits and /// satisfies physical memory needs on demand via soft page faults. If the /// function returns `true`, this indicates insufficient physical memory to /// satisfy the request. pub type extent_commit_t = unsafe extern "C" fn( extent_hooks: *mut extent_hooks_t, addr: *mut c_void, size: size_t, offset: size_t, length: size_t, arena_ind: c_uint, ) -> c_bool; /// Extent decommit function. /// /// Decommits any physical memory that is backing pages within an extent at /// given `addr` and `size` at `offset` bytes, extending for `length` on behalf of arena /// `arena_ind`, returning `false` upon success, in which case the pages will be /// committed via the extent commit function before being reused. /// /// If the function returns `true`, this indicates opt-out from decommit; the /// memory remains committed and available for future use, in which case it will /// be automatically retained for later reuse. pub type extent_decommit_t = unsafe extern "C" fn( extent_hooks: *mut extent_hooks_t, addr: *mut c_void, size: size_t, offset: size_t, length: size_t, arena_ind: c_uint, ) -> c_bool; /// Extent purge function. /// /// Discards physical pages within the virtual memory mapping associated with an /// extent at given `addr` and `size` at `offset` bytes, extending for `length` on /// behalf of arena `arena_ind`. /// /// A lazy extent purge function (e.g. implemented via `madvise(...MADV_FREE)`) /// can delay purging indefinitely and leave the pages within the purged virtual /// memory range in an indeterminite state, whereas a forced extent purge /// function immediately purges, and the pages within the virtual memory range /// will be zero-filled the next time they are accessed. If the function returns /// `true`, this indicates failure to purge. pub type extent_purge_t = unsafe extern "C" fn( extent_hooks: *mut extent_hooks_t, addr: *mut c_void, size: size_t, offset: size_t, length: size_t, arena_ind: c_uint, ) -> c_bool; /// Extent split function. /// /// Optionally splits an extent at given `addr` and `size` into two adjacent /// extents, the first of `size_a` bytes, and the second of `size_b` bytes, /// operating on `committed`/decommitted memory as indicated, on behalf of arena /// `arena_ind`, returning `false` upon success. /// /// If the function returns `true`, this indicates that the extent remains /// unsplit and therefore should continue to be operated on as a whole. pub type extent_split_t = unsafe extern "C" fn( extent_hooks: *mut extent_hooks_t, addr: *mut c_void, size: size_t, size_a: size_t, size_b: size_t, committed: c_bool, arena_ind: c_uint, ) -> c_bool; /// Extent merge function. /// /// Optionally merges adjacent extents, at given `addr_a` and `size_a` with given /// `addr_b` and `size_b` into one contiguous extent, operating on /// `committed`/decommitted memory as indicated, on behalf of arena `arena_ind`, /// returning `false` upon success. /// /// If the function returns `true`, this indicates that the extents remain /// distinct mappings and therefore should continue to be operated on /// independently. pub type extent_merge_t = unsafe extern "C" fn( extent_hooks: *mut extent_hooks_t, addr_a: *mut c_void, size_a: size_t, addr_b: *mut c_void, size_b: size_t, committed: c_bool, arena_ind: c_uint, ) -> c_bool; // These symbols are used by jemalloc on android but the really old android // we're building on doesn't have them defined, so just make sure the symbols // are available. #[no_mangle] #[cfg(target_os = "android")] #[doc(hidden)] pub extern "C" fn pthread_atfork( _prefork: *mut u8, _postfork_parent: *mut u8, _postfork_child: *mut u8, ) -> i32 { 0 } #[allow(missing_docs)] mod env; pub use env::*;