| //! 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) |
| )] |
| #![deny(missing_docs, intra_doc_link_resolution_failure)] |
| |
| extern crate libc; |
| |
| use libc::{c_char, c_int, c_uint, c_void, size_t}; |
| type c_bool = c_int; |
| |
| /// 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 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 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 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. |
| #[inline] |
| pub fn MALLOCX_TCACHE_NONE() -> c_int { |
| MALLOCX_TCACHE(!0) |
| } |
| |
| /// 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 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 = "_rjem_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 = "_rjem_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 = "_rjem_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 = "_rjem_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 = "_rjem_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 = "_rjem_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 = "_rjem_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 = "_rjem_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 = "_rjem_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 = "_rjem_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. |
| /// |
| /// 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 = "_rjem_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. |
| /// |
| /// If `ptr` is null, no action occurs. |
| /// |
| /// # 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 |
| /// * the memory region referenced by `ptr` has been deallocated. |
| #[cfg_attr(prefixed, link_name = "_rjem_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 = "_rjem_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 = "_rjem_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 = "_rjem_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 = "_rjem_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 = "_rjem_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 = "_rjem_malloc_stats_print")] |
| pub fn malloc_stats_print( |
| write_cb: Option<unsafe extern "C" fn(*mut c_void, *const c_char)>, |
| 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 = "_rjem_malloc_message")] |
| pub static mut malloc_message: |
| Option<unsafe extern "C" fn(cbopaque: *mut c_void, s: *const c_char)>; |
| |
| /// 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 = "_rjem_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<fn>` 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<unsafe extern "C" fn(*mut extent_hooks_t, *mut c_void, size_t, c_bool, c_uint)>, |
| 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<extent_alloc_t>, |
| #[allow(missing_docs)] |
| pub dalloc: Option<extent_dalloc_t>, |
| #[allow(missing_docs)] |
| pub destroy: Option<extent_destroy_t>, |
| #[allow(missing_docs)] |
| pub commit: Option<extent_commit_t>, |
| #[allow(missing_docs)] |
| pub decommit: Option<extent_decommit_t>, |
| #[allow(missing_docs)] |
| pub purge_lazy: Option<extent_purge_t>, |
| #[allow(missing_docs)] |
| pub purge_forced: Option<extent_purge_t>, |
| #[allow(missing_docs)] |
| pub split: Option<extent_split_t>, |
| #[allow(missing_docs)] |
| pub merge: Option<extent_merge_t>, |
| } |
| |
| /// 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.<i>.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.<i>.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 |
| } |