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