1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
#![no_std]
#![allow(non_camel_case_types)]
use {core::ffi::c_void, core::usize};
#[cfg_attr(
feature = "cache-friendly",
deprecated(
since = "0.2.28",
note = "Crate `snmalloc-sys` enables cache-friendly feature flag, \
which is deprecated and no longer has any effect. \
It may be removed in a future release"))]
extern "C" {
/// Allocate the memory with the given alignment and size.
/// On success, it returns a pointer pointing to the required memory address.
/// On failure, it returns a null pointer.
/// The client must assure the following things:
/// - `alignment` is greater than zero
/// - `alignment` is a power of 2
/// The program may be forced to abort if the constrains are not full-filled.
pub fn rust_alloc(alignment: usize, size: usize) -> *mut c_void;
/// De-allocate the memory at the given address with the given alignment and size.
/// The client must assure the following things:
/// - the memory is acquired using the same allocator and the pointer points to the start position.
/// - `alignment` and `size` is the same as allocation
/// The program may be forced to abort if the constrains are not full-filled.
pub fn rust_dealloc(ptr: *mut c_void, alignment: usize, size: usize) -> c_void;
/// Behaves like rust_alloc, but also ensures that the contents are set to zero before being returned.
pub fn rust_alloc_zeroed(alignment: usize, size: usize) -> *mut c_void;
/// Re-allocate the memory at the given address with the given alignment and size.
/// On success, it returns a pointer pointing to the required memory address.
/// The memory content within the `new_size` will remains the same as previous.
/// On failure, it returns a null pointer. In this situation, the previous memory is not returned to the allocator.
/// The client must assure the following things:
/// - the memory is acquired using the same allocator and the pointer points to the start position
/// - `alignment` and `old_size` is the same as allocation
/// - `alignment` fulfills all the requirements as `rust_alloc`
/// The program may be forced to abort if the constrains are not full-filled.
pub fn rust_realloc(
ptr: *mut c_void,
alignment: usize,
old_size: usize,
new_size: usize,
) -> *mut c_void;
/// Allocate `count` items of `size` length each.
/// Returns `null` if `count * size` overflows or on out-of-memory.
/// All items are initialized to zero.
pub fn sn_calloc(count: usize, size: usize) -> *mut c_void;
/// Allocate `size` bytes.
/// Returns pointer to the allocated memory or null if out of memory.
/// Returns a unique pointer if called with `size` 0.
pub fn sn_malloc(size: usize) -> *mut c_void;
/// Re-allocate memory to `newsize` bytes.
/// Return pointer to the allocated memory or null if out of memory. If null
/// is returned, the pointer `p` is not freed. Otherwise the original
/// pointer is either freed or returned as the reallocated result (in case
/// it fits in-place with the new size).
/// If `p` is null, it behaves as [`sn_malloc`]. If `newsize` is larger than
/// the original `size` allocated for `p`, the bytes after `size` are
/// uninitialized.
pub fn sn_realloc(p: *mut c_void, newsize: usize) -> *mut c_void;
/// Free previously allocated memory.
/// The pointer `p` must have been allocated before (or be null).
pub fn sn_free(p: *mut c_void);
/// Return the available bytes in a memory block.
pub fn sn_malloc_usable_size(p: *const c_void) -> usize;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_zero_allocs_correctly() {
let ptr = unsafe { rust_alloc_zeroed(8, 1024) } as *mut u8 as *mut [u8; 1024];
unsafe {
assert!((*ptr).iter().all(|x| *x == 0));
};
unsafe { rust_dealloc(ptr as *mut c_void, 8, 1024) };
}
#[test]
fn it_frees_memory_malloc() {
let ptr = unsafe { rust_alloc(8, 8) } as *mut u8;
unsafe {
*ptr = 127;
assert_eq!(*ptr, 127)
};
unsafe { rust_dealloc(ptr as *mut c_void, 8, 8) };
}
#[test]
fn it_frees_memory_sn_malloc() {
let ptr = unsafe { sn_malloc(8) } as *mut u8;
unsafe { sn_free(ptr as *mut c_void) };
}
#[test]
fn it_frees_memory_sn_realloc() {
let ptr = unsafe { sn_malloc(8) } as *mut u8;
let ptr = unsafe { sn_realloc(ptr as *mut c_void, 8) } as *mut u8;
unsafe { sn_free(ptr as *mut c_void) };
}
#[test]
fn it_reallocs_correctly() {
let mut ptr = unsafe { rust_alloc(8, 8) } as *mut u8;
unsafe {
*ptr = 127;
assert_eq!(*ptr, 127)
};
ptr = unsafe { rust_realloc(ptr as *mut c_void, 8, 8, 16) } as *mut u8;
unsafe { assert_eq!(*ptr, 127) };
unsafe { rust_dealloc(ptr as *mut c_void, 8, 16) };
}
#[test]
fn it_calculates_usable_size() {
let ptr = unsafe { sn_malloc(32) } as *mut u8;
let usable_size = unsafe { sn_malloc_usable_size(ptr as *mut c_void) };
assert!(
usable_size >= 32,
"usable_size should at least equal to the allocated size"
);
}
}