aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLibravatar vnugent <public@vaughnnugent.com>2023-03-15 17:40:51 -0400
committerLibravatar vnugent <public@vaughnnugent.com>2023-03-15 17:40:51 -0400
commit6d2897cf5e55ae0df5c22d99a0b3f4097f8afecb (patch)
tree04448fd7f3c526761df0987c449103035e6f7a44
parentfe8484fd13f16bed47ae779e34b46d6be5b8bf11 (diff)
Update rpmalloc to #847fb52
-rw-r--r--lib/WinRpMalloc/src/WinRpMalloc.vcxproj1
-rw-r--r--lib/WinRpMalloc/src/package.json2
-rw-r--r--lib/WinRpMalloc/src/rpmalloc.c166
-rw-r--r--lib/WinRpMalloc/src/rpmalloc.h592
4 files changed, 401 insertions, 360 deletions
diff --git a/lib/WinRpMalloc/src/WinRpMalloc.vcxproj b/lib/WinRpMalloc/src/WinRpMalloc.vcxproj
index 70c9d87..69a1bdf 100644
--- a/lib/WinRpMalloc/src/WinRpMalloc.vcxproj
+++ b/lib/WinRpMalloc/src/WinRpMalloc.vcxproj
@@ -159,7 +159,6 @@
<ClInclude Include="framework.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="rpmalloc.h" />
- <ClInclude Include="rpnew.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.c" />
diff --git a/lib/WinRpMalloc/src/package.json b/lib/WinRpMalloc/src/package.json
index 5717014..35a1ca6 100644
--- a/lib/WinRpMalloc/src/package.json
+++ b/lib/WinRpMalloc/src/package.json
@@ -1,5 +1,5 @@
{
- "Description": "A project to maintain an x64 Windows dll for RpMalloc by Mattias Jansson with some basic defaults for .NET loading",
+ "Description": "A project to maintain an x64 Windows dll for RpMalloc by Mattias Jansson with some basic defaults for .NET loading. The debug output contains the debug MVCR libs and debug symbols.",
"Authors": "Vaughn Nugent",
"Copyright": "Copyright &copy; 2023 Vaughn Nugent",
"Version": "0.1.1",
diff --git a/lib/WinRpMalloc/src/rpmalloc.c b/lib/WinRpMalloc/src/rpmalloc.c
index 9228cd2..249d008 100644
--- a/lib/WinRpMalloc/src/rpmalloc.c
+++ b/lib/WinRpMalloc/src/rpmalloc.c
@@ -13,12 +13,11 @@
#include "pch.h"
#include "rpmalloc.h"
-
-////////////
-///
-/// Build time configurable limits
-///
-//////
+ ////////////
+ ///
+ /// Build time configurable limits
+ ///
+ //////
#if defined(__clang__)
#pragma clang diagnostic ignored "-Wunused-macros"
@@ -34,11 +33,12 @@
#pragma GCC diagnostic ignored "-Wunused-function"
#endif
-#if defined(__GNUC__) || defined(__clang__)
#if !defined(__has_builtin)
#define __has_builtin(b) 0
#endif
+#if defined(__GNUC__) || defined(__clang__)
+
#if __has_builtin(__builtin_memcpy_inline)
#define _rpmalloc_memcpy_const(x, y, s) __builtin_memcpy_inline(x, y, s)
#else
@@ -63,6 +63,20 @@
#define _rpmalloc_memset_const(x, y, s) memset(x, y, s)
#endif
+#if __has_builtin(__builtin_assume)
+#define rpmalloc_assume(cond) __builtin_assume(cond)
+#elif defined(__GNUC__)
+#define rpmalloc_assume(cond) \
+ do { \
+ if (!__builtin_expect(cond, false)) \
+ __builtin_unreachable(); \
+ } while (0)
+#elif defined(_MSC_VER)
+#define rpmalloc_assume(cond) __assume(cond)
+#else
+#define rpmalloc_assume(cond) 0
+#endif
+
#ifndef HEAP_ARRAY_SIZE
//! Size of heap hashmap
#define HEAP_ARRAY_SIZE 47
@@ -299,7 +313,7 @@ static FORCEINLINE int atomic_cas_ptr(atomicptr_t* dst, void* val, void* ref
#define EXPECTED(x) __builtin_expect((x), 1)
#define UNEXPECTED(x) __builtin_expect((x), 0)
-
+
#endif
////////////
@@ -797,11 +811,11 @@ get_thread_id(void) {
__asm__ volatile ("mrs %0, tpidr_el0" : "=r" (tid));
# endif
# else
- tid = (uintptr_t)((void*)get_thread_heap_raw());
+# error This platform needs implementation of get_thread_id()
# endif
return tid;
#else
- return (uintptr_t)((void*)get_thread_heap_raw());
+# error This platform needs implementation of get_thread_id()
#endif
}
@@ -835,12 +849,12 @@ _rpmalloc_spin(void) {
#elif defined(__aarch64__) || (defined(__arm__) && __ARM_ARCH >= 7)
__asm__ volatile("yield" ::: "memory");
#elif defined(__powerpc__) || defined(__powerpc64__)
- // No idea if ever been compiled in such archs but ... as precaution
+ // No idea if ever been compiled in such archs but ... as precaution
__asm__ volatile("or 27,27,27");
#elif defined(__sparc__)
__asm__ volatile("rd %ccr, %g0 \n\trd %ccr, %g0 \n\trd %ccr, %g0");
#else
- struct timespec ts = {0};
+ struct timespec ts = { 0 };
nanosleep(&ts, 0);
#endif
}
@@ -869,7 +883,7 @@ _rpmalloc_thread_destructor(void* value) {
static void
_rpmalloc_set_name(void* address, size_t size) {
#if defined(__linux__) || defined(__ANDROID__)
- const char *name = _memory_huge_pages ? _memory_config.huge_page_name : _memory_config.page_name;
+ const char* name = _memory_huge_pages ? _memory_config.huge_page_name : _memory_config.page_name;
if (address == MAP_FAILED || !name)
return;
// If the kernel does not support CONFIG_ANON_VMA_NAME or if the call fails
@@ -928,7 +942,8 @@ _rpmalloc_mmap_os(size_t size, size_t* offset) {
if (_memory_config.map_fail_callback) {
if (_memory_config.map_fail_callback(size + padding))
return _rpmalloc_mmap_os(size, offset);
- } else {
+ }
+ else {
rpmalloc_assert(ptr, "Failed to map virtual memory block");
}
return 0;
@@ -968,7 +983,8 @@ _rpmalloc_mmap_os(size_t size, size_t* offset) {
if (_memory_config.map_fail_callback) {
if (_memory_config.map_fail_callback(size + padding))
return _rpmalloc_mmap_os(size, offset);
- } else if (errno != ENOMEM) {
+ }
+ else if (errno != ENOMEM) {
rpmalloc_assert((ptr != MAP_FAILED) && ptr, "Failed to map virtual memory block");
}
return 0;
@@ -1011,7 +1027,8 @@ _rpmalloc_unmap_os(void* address, size_t size, size_t offset, size_t release) {
if (munmap(address, release)) {
rpmalloc_assert(0, "Failed to unmap virtual memory block");
}
- } else {
+ }
+ else {
#if defined(MADV_FREE_REUSABLE)
int ret;
while ((ret = madvise(address, size, MADV_FREE_REUSABLE)) == -1 && (errno == EAGAIN))
@@ -1028,12 +1045,12 @@ _rpmalloc_unmap_os(void* address, size_t size, size_t offset, size_t release) {
#endif
rpmalloc_assert(0, "Failed to madvise virtual memory block as free");
}
- }
+ }
#endif
#endif
if (release)
_rpmalloc_stat_sub(&_mapped_pages_os, release >> _memory_page_size_shift);
-}
+ }
static void
_rpmalloc_span_mark_as_subspan_unless_master(span_t* master, span_t* subspan, size_t span_count);
@@ -1316,7 +1333,8 @@ free_list_partial_init(void** list, void** first_block, void* page_start, void*
next_block = pointer_offset(next_block, block_size);
}
*((void**)free_block) = 0;
- } else {
+ }
+ else {
*list = 0;
}
return block_count;
@@ -1324,7 +1342,7 @@ free_list_partial_init(void** list, void** first_block, void* page_start, void*
//! Initialize an unused span (from cache or mapped) to be new active span, putting the initial free list in heap class free list
static void*
-_rpmalloc_span_initialize_new(heap_t* heap, heap_size_class_t* heap_size_class, span_t* span, uint32_t class_idx) {
+_rpmalloc_span_initialize_new(heap_t * heap, heap_size_class_t * heap_size_class, span_t * span, uint32_t class_idx) {
rpmalloc_assert(span->span_count == 1, "Internal failure");
size_class_t* size_class = _memory_size_class + class_idx;
span->size_class = class_idx;
@@ -1338,13 +1356,14 @@ _rpmalloc_span_initialize_new(heap_t* heap, heap_size_class_t* heap_size_class,
//Setup free list. Only initialize one system page worth of free blocks in list
void* block;
- span->free_list_limit = free_list_partial_init(&heap_size_class->free_list, &block,
+ span->free_list_limit = free_list_partial_init(&heap_size_class->free_list, &block,
span, pointer_offset(span, SPAN_HEADER_SIZE), size_class->block_count, size_class->block_size);
//Link span as partial if there remains blocks to be initialized as free list, or full if fully initialized
if (span->free_list_limit < span->block_count) {
_rpmalloc_span_double_link_list_add(&heap_size_class->partial_span, span);
span->used_count = span->free_list_limit;
- } else {
+ }
+ else {
#if RPMALLOC_FIRST_CLASS_HEAPS
_rpmalloc_span_double_link_list_add(&heap->full_span[class_idx], span);
#endif
@@ -1392,7 +1411,8 @@ _rpmalloc_span_finalize(heap_t* heap, size_t iclass, span_t* span, span_t** list
}
if (last_block) {
*((void**)last_block) = free_list;
- } else {
+ }
+ else {
span->free_list = free_list;
}
heap->size_class[iclass].free_list = 0;
@@ -1442,7 +1462,7 @@ _rpmalloc_global_cache_finalize(global_cache_t* cache) {
static void
_rpmalloc_global_cache_insert_spans(span_t** span, size_t span_count, size_t count) {
- const size_t cache_limit = (span_count == 1) ?
+ const size_t cache_limit = (span_count == 1) ?
GLOBAL_CACHE_MULTIPLIER * MAX_THREAD_SPAN_CACHE :
GLOBAL_CACHE_MULTIPLIER * (MAX_THREAD_SPAN_LARGE_CACHE - (span_count >> 1));
@@ -1479,10 +1499,11 @@ _rpmalloc_global_cache_insert_spans(span_t** span, size_t span_count, size_t cou
span_t* current_span = span[ispan];
// Keep master spans that has remaining subspans to avoid dangling them
if ((current_span->flags & SPAN_FLAG_MASTER) &&
- (atomic_load32(&current_span->remaining_spans) > (int32_t)current_span->span_count)) {
+ (atomic_load32(&current_span->remaining_spans) > (int32_t)current_span->span_count)) {
current_span->next = keep;
keep = current_span;
- } else {
+ }
+ else {
_rpmalloc_span_unmap(current_span);
}
}
@@ -1496,7 +1517,7 @@ _rpmalloc_global_cache_insert_spans(span_t** span, size_t span_count, size_t cou
for (; islot < cache->count; ++islot) {
span_t* current_span = cache->span[islot];
if (!(current_span->flags & SPAN_FLAG_MASTER) || ((current_span->flags & SPAN_FLAG_MASTER) &&
- (atomic_load32(&current_span->remaining_spans) <= (int32_t)current_span->span_count))) {
+ (atomic_load32(&current_span->remaining_spans) <= (int32_t)current_span->span_count))) {
_rpmalloc_span_unmap(current_span);
cache->span[islot] = keep;
break;
@@ -1517,7 +1538,7 @@ _rpmalloc_global_cache_insert_spans(span_t** span, size_t span_count, size_t cou
atomic_store32_release(&cache->lock, 0);
}
-}
+ }
static size_t
_rpmalloc_global_cache_extract_spans(span_t** span, size_t span_count, size_t count) {
@@ -1546,7 +1567,7 @@ _rpmalloc_global_cache_extract_spans(span_t** span, size_t span_count, size_t co
#if ENABLE_ASSERTS
for (size_t ispan = 0; ispan < extract_count; ++ispan) {
- assert(span[ispan]->span_count == span_count);
+ rpmalloc_assert(span[ispan]->span_count == span_count, "Global cache span count mismatch");
}
#endif
@@ -1575,7 +1596,7 @@ _rpmalloc_heap_set_reserved_spans(heap_t* heap, span_t* master, span_t* reserve,
//! Adopt the deferred span cache list, optionally extracting the first single span for immediate re-use
static void
-_rpmalloc_heap_cache_adopt_deferred(heap_t* heap, span_t** single_span) {
+_rpmalloc_heap_cache_adopt_deferred(heap_t * heap, span_t * *single_span) {
span_t* span = (span_t*)((void*)atomic_exchange_ptr_acquire(&heap->span_free_deferred, 0));
while (span) {
span_t* next_span = (span_t*)span->free_list;
@@ -1593,10 +1614,12 @@ _rpmalloc_heap_cache_adopt_deferred(heap_t* heap, span_t** single_span) {
*single_span = span;
else
_rpmalloc_heap_cache_insert(heap, span);
- } else {
+ }
+ else {
if (span->size_class == SIZE_CLASS_HUGE) {
_rpmalloc_deallocate_huge(span);
- } else {
+ }
+ else {
rpmalloc_assert(span->size_class == SIZE_CLASS_LARGE, "Span size class invalid");
rpmalloc_assert(heap->full_span_count, "Heap span counter corrupted");
--heap->full_span_count;
@@ -1623,7 +1646,8 @@ _rpmalloc_heap_unmap(heap_t* heap) {
span_t* span = (span_t*)((uintptr_t)heap & _memory_span_mask);
_rpmalloc_span_unmap(span);
}
- } else {
+ }
+ else {
if (atomic_decr32(&heap->master_heap->child_count) == 0) {
_rpmalloc_heap_unmap(heap->master_heap);
}
@@ -1668,7 +1692,8 @@ _rpmalloc_heap_global_finalize(heap_t* heap) {
heap_t* list_heap = _memory_heaps[list_idx];
if (list_heap == heap) {
_memory_heaps[list_idx] = heap->next_heap;
- } else {
+ }
+ else {
while (list_heap->next_heap != heap)
list_heap = list_heap->next_heap;
list_heap->next_heap = heap->next_heap;
@@ -1703,7 +1728,8 @@ _rpmalloc_heap_cache_insert(heap_t* heap, span_t* span) {
#endif
span_cache->count = remain_count;
}
- } else {
+ }
+ else {
size_t cache_idx = span_count - 2;
span_large_cache_t* span_cache = heap->span_large_cache + cache_idx;
span_cache->span[span_cache->count++] = span;
@@ -1752,7 +1778,8 @@ _rpmalloc_heap_thread_cache_deferred_extract(heap_t* heap, size_t span_count) {
span_t* span = 0;
if (span_count == 1) {
_rpmalloc_heap_cache_adopt_deferred(heap, &span);
- } else {
+ }
+ else {
_rpmalloc_heap_cache_adopt_deferred(heap, 0);
span = _rpmalloc_heap_thread_cache_extract(heap, span_count);
}
@@ -1776,7 +1803,8 @@ _rpmalloc_heap_global_cache_extract(heap_t* heap, size_t span_count) {
if (span_count == 1) {
span_cache = &heap->span_cache;
wanted_count = THREAD_SPAN_CACHE_TRANSFER;
- } else {
+ }
+ else {
span_cache = (span_cache_t*)(heap->span_large_cache + (span_count - 2));
wanted_count = THREAD_SPAN_LARGE_CACHE_TRANSFER;
}
@@ -1990,7 +2018,8 @@ _rpmalloc_heap_allocate(int first_class) {
if (!heap)
heap = _rpmalloc_heap_allocate_new();
atomic_store32_release(&_memory_global_lock, 0);
- _rpmalloc_heap_cache_adopt_deferred(heap, 0);
+ if (heap)
+ _rpmalloc_heap_cache_adopt_deferred(heap, 0);
return heap;
}
@@ -2001,7 +2030,7 @@ _rpmalloc_heap_release(void* heapptr, int first_class, int release_cache) {
return;
//Release thread cache spans back to global cache
_rpmalloc_heap_cache_adopt_deferred(heap, 0);
- if (release_cache || heap->finalize) {
+ if (release_cache || heap->finalize) {
#if ENABLE_THREAD_CACHE
for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {
span_cache_t* span_cache;
@@ -2015,7 +2044,8 @@ _rpmalloc_heap_release(void* heapptr, int first_class, int release_cache) {
if (heap->finalize) {
for (size_t ispan = 0; ispan < span_cache->count; ++ispan)
_rpmalloc_span_unmap(span_cache->span[ispan]);
- } else {
+ }
+ else {
_rpmalloc_stat_add64(&heap->thread_to_global, span_cache->count * (iclass + 1) * _memory_span_size);
_rpmalloc_stat_add(&heap->span_use[iclass].spans_to_global, span_cache->count);
_rpmalloc_global_cache_insert_spans(span_cache->span, iclass + 1, span_cache->count);
@@ -2125,8 +2155,9 @@ free_list_pop(void** list) {
//! Allocate a small/medium sized memory block from the given heap
static void*
-_rpmalloc_allocate_from_heap_fallback(heap_t* heap, heap_size_class_t* heap_size_class, uint32_t class_idx) {
+_rpmalloc_allocate_from_heap_fallback(heap_t * heap, heap_size_class_t * heap_size_class, uint32_t class_idx) {
span_t* span = heap_size_class->partial_span;
+ rpmalloc_assume(heap);
if (EXPECTED(span != 0)) {
rpmalloc_assert(span->block_count == _memory_size_class[span->size_class].block_count, "Span block count corrupted");
rpmalloc_assert(!_rpmalloc_span_is_fully_utilized(span), "Internal failure");
@@ -2136,7 +2167,8 @@ _rpmalloc_allocate_from_heap_fallback(heap_t* heap, heap_size_class_t* heap_size
block = free_list_pop(&span->free_list);
heap_size_class->free_list = span->free_list;
span->free_list = 0;
- } else {
+ }
+ else {
//If the span did not fully initialize free list, link up another page worth of blocks
void* block_start = pointer_offset(span, SPAN_HEADER_SIZE + ((size_t)span->free_list_limit * span->block_size));
span->free_list_limit += free_list_partial_init(&heap_size_class->free_list, &block,
@@ -2288,7 +2320,7 @@ _rpmalloc_aligned_allocate(heap_t* heap, size_t alignment, size_t size) {
}
#endif
- if ((alignment <= SPAN_HEADER_SIZE) && (size < _memory_medium_size_limit)) {
+ if ((alignment <= SPAN_HEADER_SIZE) && ((size + SPAN_HEADER_SIZE) < _memory_medium_size_limit)) {
// If alignment is less or equal to span header size (which is power of two),
// and size aligned to span header size multiples is less than size + alignment,
// then use natural alignment of blocks to provide alignment
@@ -2362,8 +2394,8 @@ retry:
ptr = (void*)(((uintptr_t)ptr & ~(uintptr_t)align_mask) + alignment);
if (((size_t)pointer_diff(ptr, span) >= _memory_span_size) ||
- (pointer_offset(ptr, size) > pointer_offset(span, mapped_size)) ||
- (((uintptr_t)ptr & _memory_span_mask) != (uintptr_t)span)) {
+ (pointer_offset(ptr, size) > pointer_offset(span, mapped_size)) ||
+ (((uintptr_t)ptr & _memory_span_mask) != (uintptr_t)span)) {
_rpmalloc_unmap(span, mapped_size, align_offset, mapped_size);
++num_pages;
if (num_pages > limit_pages) {
@@ -2522,14 +2554,16 @@ _rpmalloc_deallocate_large(span_t* span) {
heap->spans_reserved = span->span_count;
if (span->flags & SPAN_FLAG_MASTER) {
heap->span_reserve_master = span;
- } else { //SPAN_FLAG_SUBSPAN
+ }
+ else { //SPAN_FLAG_SUBSPAN
span_t* master = (span_t*)pointer_offset(span, -(intptr_t)((size_t)span->offset_from_master * _memory_span_size));
heap->span_reserve_master = master;
rpmalloc_assert(master->flags & SPAN_FLAG_MASTER, "Span flag corrupted");
rpmalloc_assert(atomic_load32(&master->remaining_spans) >= (int32_t)span->span_count, "Master span count corrupted");
}
_rpmalloc_stat_inc(&heap->span_use[idx].spans_to_reserved);
- } else {
+ }
+ else {
//Insert into cache list
_rpmalloc_heap_cache_insert(heap, span);
}
@@ -2606,7 +2640,8 @@ _rpmalloc_reallocate(heap_t* heap, void* p, size_t size, size_t oldsize, unsigne
memmove(block, p, oldsize);
return block;
}
- } else if (span->size_class == SIZE_CLASS_LARGE) {
+ }
+ else if (span->size_class == SIZE_CLASS_LARGE) {
//Large block
size_t total_size = size + SPAN_HEADER_SIZE;
size_t num_spans = total_size >> _memory_span_size_shift;
@@ -2622,7 +2657,8 @@ _rpmalloc_reallocate(heap_t* heap, void* p, size_t size, size_t oldsize, unsigne
memmove(block, p, oldsize);
return block;
}
- } else {
+ }
+ else {
//Oversized block
size_t total_size = size + SPAN_HEADER_SIZE;
size_t num_pages = total_size >> _memory_page_size_shift;
@@ -2640,7 +2676,8 @@ _rpmalloc_reallocate(heap_t* heap, void* p, size_t size, size_t oldsize, unsigne
return block;
}
}
- } else {
+ }
+ else {
oldsize = 0;
}
@@ -2663,7 +2700,7 @@ _rpmalloc_reallocate(heap_t* heap, void* p, size_t size, size_t oldsize, unsigne
static void*
_rpmalloc_aligned_reallocate(heap_t* heap, void* ptr, size_t alignment, size_t size, size_t oldsize,
- unsigned int flags) {
+ unsigned int flags) {
if (alignment <= SMALL_GRANULARITY)
return _rpmalloc_reallocate(heap, ptr, size, oldsize, flags);
@@ -2818,7 +2855,8 @@ rpmalloc_initialize_config(const rpmalloc_config_t* config) {
#endif
}
#endif
- } else {
+ }
+ else {
if (_memory_config.enable_huge_pages)
_memory_huge_pages = 1;
}
@@ -2877,7 +2915,8 @@ rpmalloc_initialize_config(const rpmalloc_config_t* config) {
_memory_span_size = _memory_default_span_size;
_memory_span_size_shift = _memory_default_span_size_shift;
_memory_span_mask = _memory_default_span_mask;
- } else {
+ }
+ else {
size_t span_size = _memory_config.span_size;
if (span_size > (256 * 1024))
span_size = (256 * 1024);
@@ -2891,7 +2930,7 @@ rpmalloc_initialize_config(const rpmalloc_config_t* config) {
}
#endif
- _memory_span_map_count = ( _memory_config.span_map_count ? _memory_config.span_map_count : DEFAULT_SPAN_MAP_COUNT);
+ _memory_span_map_count = (_memory_config.span_map_count ? _memory_config.span_map_count : DEFAULT_SPAN_MAP_COUNT);
if ((_memory_span_size * _memory_span_map_count) < _memory_page_size)
_memory_span_map_count = (_memory_page_size / _memory_span_size);
if ((_memory_page_size >= _memory_span_size) && ((_memory_span_map_count * _memory_span_size) % _memory_page_size))
@@ -2926,8 +2965,10 @@ rpmalloc_initialize_config(const rpmalloc_config_t* config) {
_memory_medium_size_limit = MEDIUM_SIZE_LIMIT;
for (iclass = 0; iclass < MEDIUM_CLASS_COUNT; ++iclass) {
size_t size = SMALL_SIZE_LIMIT + ((iclass + 1) * MEDIUM_GRANULARITY);
- if (size > _memory_medium_size_limit)
+ if (size > _memory_medium_size_limit) {
+ _memory_medium_size_limit = SMALL_SIZE_LIMIT + (iclass * MEDIUM_GRANULARITY);
break;
+ }
_memory_size_class[SMALL_CLASS_COUNT + iclass].block_size = (uint32_t)size;
_rpmalloc_adjust_size_class(SMALL_CLASS_COUNT + iclass);
}
@@ -2969,7 +3010,7 @@ rpmalloc_finalize(void) {
_memory_global_reserve_count = 0;
_memory_global_reserve = 0;
}
- atomic_store32_release(&_memory_global_lock, 0);
+ atomic_store32_release(&_memory_global_lock, 0);
//Free all thread caches and fully free spans
for (size_t list_idx = 0; list_idx < HEAP_ARRAY_SIZE; ++list_idx) {
@@ -3101,7 +3142,7 @@ rprealloc(void* ptr, size_t size) {
extern RPMALLOC_ALLOCATOR void*
rpaligned_realloc(void* ptr, size_t alignment, size_t size, size_t oldsize,
- unsigned int flags) {
+ unsigned int flags) {
#if ENABLE_VALIDATE_ARGS
if ((size + alignment < size) || (alignment > _memory_page_size)) {
errno = EINVAL;
@@ -3150,7 +3191,7 @@ rpmemalign(size_t alignment, size_t size) {
}
extern inline int
-rpposix_memalign(void **memptr, size_t alignment, size_t size) {
+rpposix_memalign(void** memptr, size_t alignment, size_t size) {
if (memptr)
*memptr = rpaligned_alloc(alignment, size);
else
@@ -3183,7 +3224,7 @@ rpmalloc_thread_statistics(rpmalloc_thread_statistics_t* stats) {
if (span->free_list_limit < block_count)
block_count = span->free_list_limit;
free_count += (block_count - span->used_count);
- stats->sizecache = free_count * size_class->block_size;
+ stats->sizecache += free_count * size_class->block_size;
span = span->next;
}
}
@@ -3195,14 +3236,14 @@ rpmalloc_thread_statistics(rpmalloc_thread_statistics_t* stats) {
span_cache = &heap->span_cache;
else
span_cache = (span_cache_t*)(heap->span_large_cache + (iclass - 1));
- stats->spancache = span_cache->count * (iclass + 1) * _memory_span_size;
+ stats->spancache += span_cache->count * (iclass + 1) * _memory_span_size;
}
#endif
span_t* deferred = (span_t*)atomic_load_ptr(&heap->span_free_deferred);
while (deferred) {
if (deferred->size_class != SIZE_CLASS_HUGE)
- stats->spancache = (size_t)deferred->span_count * _memory_span_size;
+ stats->spancache += (size_t)deferred->span_count * _memory_span_size;
deferred = (span_t*)deferred->free_list;
}
@@ -3386,6 +3427,7 @@ rpmalloc_heap_acquire(void) {
// heap is cleared with rpmalloc_heap_free_all(). Also heaps guaranteed to be
// pristine from the dedicated orphan list can be used.
heap_t* heap = _rpmalloc_heap_allocate(1);
+ rpmalloc_assume(heap != NULL);
heap->owner_thread = 0;
_rpmalloc_stat_inc(&_memory_active_heaps);
return heap;
@@ -3469,7 +3511,7 @@ rpmalloc_heap_aligned_realloc(rpmalloc_heap_t* heap, void* ptr, size_t alignment
return 0;
}
#endif
- return _rpmalloc_aligned_reallocate(heap, ptr, alignment, size, 0, flags);
+ return _rpmalloc_aligned_reallocate(heap, ptr, alignment, size, 0, flags);
}
extern inline void
diff --git a/lib/WinRpMalloc/src/rpmalloc.h b/lib/WinRpMalloc/src/rpmalloc.h
index 3806653..111ff27 100644
--- a/lib/WinRpMalloc/src/rpmalloc.h
+++ b/lib/WinRpMalloc/src/rpmalloc.h
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2022 Vaughn Nugent
+* Copyright (c) 2023 Vaughn Nugent
*
* Library: VNLib
* Package: WinRpMalloc
@@ -70,8 +70,8 @@ extern "C" {
# define RPMALLOC_CDECL
#endif
-//! Define RPMALLOC_CONFIGURABLE to enable configuring sizes. Will introduce
-// a very small overhead due to some size calculations not being compile time constants
+ //! Define RPMALLOC_CONFIGURABLE to enable configuring sizes. Will introduce
+ // a very small overhead due to some size calculations not being compile time constants
#ifndef RPMALLOC_CONFIGURABLE
#define RPMALLOC_CONFIGURABLE 0
#endif
@@ -89,302 +89,302 @@ extern "C" {
// a new block).
#define RPMALLOC_GROW_OR_FAIL 2
-typedef struct rpmalloc_global_statistics_t {
- //! Current amount of virtual memory mapped, all of which might not have been committed (only if ENABLE_STATISTICS=1)
- size_t mapped;
- //! Peak amount of virtual memory mapped, all of which might not have been committed (only if ENABLE_STATISTICS=1)
- size_t mapped_peak;
- //! Current amount of memory in global caches for small and medium sizes (<32KiB)
- size_t cached;
- //! Current amount of memory allocated in huge allocations, i.e larger than LARGE_SIZE_LIMIT which is 2MiB by default (only if ENABLE_STATISTICS=1)
- size_t huge_alloc;
- //! Peak amount of memory allocated in huge allocations, i.e larger than LARGE_SIZE_LIMIT which is 2MiB by default (only if ENABLE_STATISTICS=1)
- size_t huge_alloc_peak;
- //! Total amount of memory mapped since initialization (only if ENABLE_STATISTICS=1)
- size_t mapped_total;
- //! Total amount of memory unmapped since initialization (only if ENABLE_STATISTICS=1)
- size_t unmapped_total;
-} rpmalloc_global_statistics_t;
-
-typedef struct rpmalloc_thread_statistics_t {
- //! Current number of bytes available in thread size class caches for small and medium sizes (<32KiB)
- size_t sizecache;
- //! Current number of bytes available in thread span caches for small and medium sizes (<32KiB)
- size_t spancache;
- //! Total number of bytes transitioned from thread cache to global cache (only if ENABLE_STATISTICS=1)
- size_t thread_to_global;
- //! Total number of bytes transitioned from global cache to thread cache (only if ENABLE_STATISTICS=1)
- size_t global_to_thread;
- //! Per span count statistics (only if ENABLE_STATISTICS=1)
- struct {
- //! Currently used number of spans
- size_t current;
- //! High water mark of spans used
- size_t peak;
- //! Number of spans transitioned to global cache
- size_t to_global;
- //! Number of spans transitioned from global cache
- size_t from_global;
- //! Number of spans transitioned to thread cache
- size_t to_cache;
- //! Number of spans transitioned from thread cache
- size_t from_cache;
- //! Number of spans transitioned to reserved state
- size_t to_reserved;
- //! Number of spans transitioned from reserved state
- size_t from_reserved;
- //! Number of raw memory map calls (not hitting the reserve spans but resulting in actual OS mmap calls)
- size_t map_calls;
- } span_use[64];
- //! Per size class statistics (only if ENABLE_STATISTICS=1)
- struct {
- //! Current number of allocations
- size_t alloc_current;
- //! Peak number of allocations
- size_t alloc_peak;
- //! Total number of allocations
- size_t alloc_total;
- //! Total number of frees
- size_t free_total;
- //! Number of spans transitioned to cache
- size_t spans_to_cache;
- //! Number of spans transitioned from cache
- size_t spans_from_cache;
- //! Number of spans transitioned from reserved state
- size_t spans_from_reserved;
- //! Number of raw memory map calls (not hitting the reserve spans but resulting in actual OS mmap calls)
- size_t map_calls;
- } size_use[128];
-} rpmalloc_thread_statistics_t;
-
-typedef struct rpmalloc_config_t {
- //! Map memory pages for the given number of bytes. The returned address MUST be
- // aligned to the rpmalloc span size, which will always be a power of two.
- // Optionally the function can store an alignment offset in the offset variable
- // in case it performs alignment and the returned pointer is offset from the
- // actual start of the memory region due to this alignment. The alignment offset
- // will be passed to the memory unmap function. The alignment offset MUST NOT be
- // larger than 65535 (storable in an uint16_t), if it is you must use natural
- // alignment to shift it into 16 bits. If you set a memory_map function, you
- // must also set a memory_unmap function or else the default implementation will
- // be used for both. This function must be thread safe, it can be called by
- // multiple threads simultaneously.
- void* (*memory_map)(size_t size, size_t* offset);
- //! Unmap the memory pages starting at address and spanning the given number of bytes.
- // If release is set to non-zero, the unmap is for an entire span range as returned by
- // a previous call to memory_map and that the entire range should be released. The
- // release argument holds the size of the entire span range. If release is set to 0,
- // the unmap is a partial decommit of a subset of the mapped memory range.
- // If you set a memory_unmap function, you must also set a memory_map function or
- // else the default implementation will be used for both. This function must be thread
- // safe, it can be called by multiple threads simultaneously.
- void (*memory_unmap)(void* address, size_t size, size_t offset, size_t release);
- //! Called when an assert fails, if asserts are enabled. Will use the standard assert()
- // if this is not set.
- void (*error_callback)(const char* message);
- //! Called when a call to map memory pages fails (out of memory). If this callback is
- // not set or returns zero the library will return a null pointer in the allocation
- // call. If this callback returns non-zero the map call will be retried. The argument
- // passed is the number of bytes that was requested in the map call. Only used if
- // the default system memory map function is used (memory_map callback is not set).
- int (*map_fail_callback)(size_t size);
- //! Size of memory pages. The page size MUST be a power of two. All memory mapping
- // requests to memory_map will be made with size set to a multiple of the page size.
- // Used if RPMALLOC_CONFIGURABLE is defined to 1, otherwise system page size is used.
- size_t page_size;
- //! Size of a span of memory blocks. MUST be a power of two, and in [4096,262144]
- // range (unless 0 - set to 0 to use the default span size). Used if RPMALLOC_CONFIGURABLE
- // is defined to 1.
- size_t span_size;
- //! Number of spans to map at each request to map new virtual memory blocks. This can
- // be used to minimize the system call overhead at the cost of virtual memory address
- // space. The extra mapped pages will not be written until actually used, so physical
- // committed memory should not be affected in the default implementation. Will be
- // aligned to a multiple of spans that match memory page size in case of huge pages.
- size_t span_map_count;
- //! Enable use of large/huge pages. If this flag is set to non-zero and page size is
- // zero, the allocator will try to enable huge pages and auto detect the configuration.
- // If this is set to non-zero and page_size is also non-zero, the allocator will
- // assume huge pages have been configured and enabled prior to initializing the
- // allocator.
- // For Windows, see https://docs.microsoft.com/en-us/windows/desktop/memory/large-page-support
- // For Linux, see https://www.kernel.org/doc/Documentation/vm/hugetlbpage.txt
- int enable_huge_pages;
- //! Respectively allocated pages and huge allocated pages names for systems
- // supporting it to be able to distinguish among anonymous regions.
- const char *page_name;
- const char *huge_page_name;
-} rpmalloc_config_t;
-
-//! Initialize allocator with default configuration
-RPMALLOC_EXPORT int
-rpmalloc_initialize(void);
-
-//! Initialize allocator with given configuration
-RPMALLOC_EXPORT int
-rpmalloc_initialize_config(const rpmalloc_config_t* config);
-
-//! Get allocator configuration
-RPMALLOC_EXPORT const rpmalloc_config_t*
-rpmalloc_config(void);
-
-//! Finalize allocator
-RPMALLOC_EXPORT void
-rpmalloc_finalize(void);
-
-//! Initialize allocator for calling thread
-RPMALLOC_EXPORT void
-rpmalloc_thread_initialize(void);
-
-//! Finalize allocator for calling thread
-RPMALLOC_EXPORT void
-rpmalloc_thread_finalize(int release_caches);
-
-//! Perform deferred deallocations pending for the calling thread heap
-RPMALLOC_EXPORT void
-rpmalloc_thread_collect(void);
-
-//! Query if allocator is initialized for calling thread
-RPMALLOC_EXPORT int
-rpmalloc_is_thread_initialized(void);
-
-//! Get per-thread statistics
-RPMALLOC_EXPORT void
-rpmalloc_thread_statistics(rpmalloc_thread_statistics_t* stats);
-
-//! Get global statistics
-RPMALLOC_EXPORT void
-rpmalloc_global_statistics(rpmalloc_global_statistics_t* stats);
-
-//! Dump all statistics in human readable format to file (should be a FILE*)
-RPMALLOC_EXPORT void
-rpmalloc_dump_statistics(void* file);
-
-//! Allocate a memory block of at least the given size
-RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
-rpmalloc(size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(1);
-
-//! Free the given memory block
-RPMALLOC_EXPORT void
-rpfree(void* ptr);
-
-//! Allocate a memory block of at least the given size and zero initialize it
-RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
-rpcalloc(size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(1, 2);
-
-//! Reallocate the given block to at least the given size
-RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
-rprealloc(void* ptr, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2);
-
-//! Reallocate the given block to at least the given size and alignment,
-// with optional control flags (see RPMALLOC_NO_PRESERVE).
-// Alignment must be a power of two and a multiple of sizeof(void*),
-// and should ideally be less than memory page size. A caveat of rpmalloc
-// internals is that this must also be strictly less than the span size (default 64KiB)
-RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
-rpaligned_realloc(void* ptr, size_t alignment, size_t size, size_t oldsize, unsigned int flags) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(3);
-
-//! Allocate a memory block of at least the given size and alignment.
-// Alignment must be a power of two and a multiple of sizeof(void*),
-// and should ideally be less than memory page size. A caveat of rpmalloc
-// internals is that this must also be strictly less than the span size (default 64KiB)
-RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
-rpaligned_alloc(size_t alignment, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2);
-
-//! Allocate a memory block of at least the given size and alignment, and zero initialize it.
-// Alignment must be a power of two and a multiple of sizeof(void*),
-// and should ideally be less than memory page size. A caveat of rpmalloc
-// internals is that this must also be strictly less than the span size (default 64KiB)
-RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
-rpaligned_calloc(size_t alignment, size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(2, 3);
-
-//! Allocate a memory block of at least the given size and alignment.
-// Alignment must be a power of two and a multiple of sizeof(void*),
-// and should ideally be less than memory page size. A caveat of rpmalloc
-// internals is that this must also be strictly less than the span size (default 64KiB)
-RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
-rpmemalign(size_t alignment, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2);
-
-//! Allocate a memory block of at least the given size and alignment.
-// Alignment must be a power of two and a multiple of sizeof(void*),
-// and should ideally be less than memory page size. A caveat of rpmalloc
-// internals is that this must also be strictly less than the span size (default 64KiB)
-RPMALLOC_EXPORT int
-rpposix_memalign(void** memptr, size_t alignment, size_t size);
-
-//! Query the usable size of the given memory block (from given pointer to the end of block)
-RPMALLOC_EXPORT size_t
-rpmalloc_usable_size(void* ptr);
-
-//! Dummy empty function for forcing linker symbol inclusion
-RPMALLOC_EXPORT void
-rpmalloc_linker_reference(void);
+ typedef struct rpmalloc_global_statistics_t {
+ //! Current amount of virtual memory mapped, all of which might not have been committed (only if ENABLE_STATISTICS=1)
+ size_t mapped;
+ //! Peak amount of virtual memory mapped, all of which might not have been committed (only if ENABLE_STATISTICS=1)
+ size_t mapped_peak;
+ //! Current amount of memory in global caches for small and medium sizes (<32KiB)
+ size_t cached;
+ //! Current amount of memory allocated in huge allocations, i.e larger than LARGE_SIZE_LIMIT which is 2MiB by default (only if ENABLE_STATISTICS=1)
+ size_t huge_alloc;
+ //! Peak amount of memory allocated in huge allocations, i.e larger than LARGE_SIZE_LIMIT which is 2MiB by default (only if ENABLE_STATISTICS=1)
+ size_t huge_alloc_peak;
+ //! Total amount of memory mapped since initialization (only if ENABLE_STATISTICS=1)
+ size_t mapped_total;
+ //! Total amount of memory unmapped since initialization (only if ENABLE_STATISTICS=1)
+ size_t unmapped_total;
+ } rpmalloc_global_statistics_t;
+
+ typedef struct rpmalloc_thread_statistics_t {
+ //! Current number of bytes available in thread size class caches for small and medium sizes (<32KiB)
+ size_t sizecache;
+ //! Current number of bytes available in thread span caches for small and medium sizes (<32KiB)
+ size_t spancache;
+ //! Total number of bytes transitioned from thread cache to global cache (only if ENABLE_STATISTICS=1)
+ size_t thread_to_global;
+ //! Total number of bytes transitioned from global cache to thread cache (only if ENABLE_STATISTICS=1)
+ size_t global_to_thread;
+ //! Per span count statistics (only if ENABLE_STATISTICS=1)
+ struct {
+ //! Currently used number of spans
+ size_t current;
+ //! High water mark of spans used
+ size_t peak;
+ //! Number of spans transitioned to global cache
+ size_t to_global;
+ //! Number of spans transitioned from global cache
+ size_t from_global;
+ //! Number of spans transitioned to thread cache
+ size_t to_cache;
+ //! Number of spans transitioned from thread cache
+ size_t from_cache;
+ //! Number of spans transitioned to reserved state
+ size_t to_reserved;
+ //! Number of spans transitioned from reserved state
+ size_t from_reserved;
+ //! Number of raw memory map calls (not hitting the reserve spans but resulting in actual OS mmap calls)
+ size_t map_calls;
+ } span_use[64];
+ //! Per size class statistics (only if ENABLE_STATISTICS=1)
+ struct {
+ //! Current number of allocations
+ size_t alloc_current;
+ //! Peak number of allocations
+ size_t alloc_peak;
+ //! Total number of allocations
+ size_t alloc_total;
+ //! Total number of frees
+ size_t free_total;
+ //! Number of spans transitioned to cache
+ size_t spans_to_cache;
+ //! Number of spans transitioned from cache
+ size_t spans_from_cache;
+ //! Number of spans transitioned from reserved state
+ size_t spans_from_reserved;
+ //! Number of raw memory map calls (not hitting the reserve spans but resulting in actual OS mmap calls)
+ size_t map_calls;
+ } size_use[128];
+ } rpmalloc_thread_statistics_t;
+
+ typedef struct rpmalloc_config_t {
+ //! Map memory pages for the given number of bytes. The returned address MUST be
+ // aligned to the rpmalloc span size, which will always be a power of two.
+ // Optionally the function can store an alignment offset in the offset variable
+ // in case it performs alignment and the returned pointer is offset from the
+ // actual start of the memory region due to this alignment. The alignment offset
+ // will be passed to the memory unmap function. The alignment offset MUST NOT be
+ // larger than 65535 (storable in an uint16_t), if it is you must use natural
+ // alignment to shift it into 16 bits. If you set a memory_map function, you
+ // must also set a memory_unmap function or else the default implementation will
+ // be used for both. This function must be thread safe, it can be called by
+ // multiple threads simultaneously.
+ void* (*memory_map)(size_t size, size_t* offset);
+ //! Unmap the memory pages starting at address and spanning the given number of bytes.
+ // If release is set to non-zero, the unmap is for an entire span range as returned by
+ // a previous call to memory_map and that the entire range should be released. The
+ // release argument holds the size of the entire span range. If release is set to 0,
+ // the unmap is a partial decommit of a subset of the mapped memory range.
+ // If you set a memory_unmap function, you must also set a memory_map function or
+ // else the default implementation will be used for both. This function must be thread
+ // safe, it can be called by multiple threads simultaneously.
+ void (*memory_unmap)(void* address, size_t size, size_t offset, size_t release);
+ //! Called when an assert fails, if asserts are enabled. Will use the standard assert()
+ // if this is not set.
+ void (*error_callback)(const char* message);
+ //! Called when a call to map memory pages fails (out of memory). If this callback is
+ // not set or returns zero the library will return a null pointer in the allocation
+ // call. If this callback returns non-zero the map call will be retried. The argument
+ // passed is the number of bytes that was requested in the map call. Only used if
+ // the default system memory map function is used (memory_map callback is not set).
+ int (*map_fail_callback)(size_t size);
+ //! Size of memory pages. The page size MUST be a power of two. All memory mapping
+ // requests to memory_map will be made with size set to a multiple of the page size.
+ // Used if RPMALLOC_CONFIGURABLE is defined to 1, otherwise system page size is used.
+ size_t page_size;
+ //! Size of a span of memory blocks. MUST be a power of two, and in [4096,262144]
+ // range (unless 0 - set to 0 to use the default span size). Used if RPMALLOC_CONFIGURABLE
+ // is defined to 1.
+ size_t span_size;
+ //! Number of spans to map at each request to map new virtual memory blocks. This can
+ // be used to minimize the system call overhead at the cost of virtual memory address
+ // space. The extra mapped pages will not be written until actually used, so physical
+ // committed memory should not be affected in the default implementation. Will be
+ // aligned to a multiple of spans that match memory page size in case of huge pages.
+ size_t span_map_count;
+ //! Enable use of large/huge pages. If this flag is set to non-zero and page size is
+ // zero, the allocator will try to enable huge pages and auto detect the configuration.
+ // If this is set to non-zero and page_size is also non-zero, the allocator will
+ // assume huge pages have been configured and enabled prior to initializing the
+ // allocator.
+ // For Windows, see https://docs.microsoft.com/en-us/windows/desktop/memory/large-page-support
+ // For Linux, see https://www.kernel.org/doc/Documentation/vm/hugetlbpage.txt
+ int enable_huge_pages;
+ //! Respectively allocated pages and huge allocated pages names for systems
+ // supporting it to be able to distinguish among anonymous regions.
+ const char* page_name;
+ const char* huge_page_name;
+ } rpmalloc_config_t;
+
+ //! Initialize allocator with default configuration
+ RPMALLOC_EXPORT int
+ rpmalloc_initialize(void);
+
+ //! Initialize allocator with given configuration
+ RPMALLOC_EXPORT int
+ rpmalloc_initialize_config(const rpmalloc_config_t* config);
+
+ //! Get allocator configuration
+ RPMALLOC_EXPORT const rpmalloc_config_t*
+ rpmalloc_config(void);
+
+ //! Finalize allocator
+ RPMALLOC_EXPORT void
+ rpmalloc_finalize(void);
+
+ //! Initialize allocator for calling thread
+ RPMALLOC_EXPORT void
+ rpmalloc_thread_initialize(void);
+
+ //! Finalize allocator for calling thread
+ RPMALLOC_EXPORT void
+ rpmalloc_thread_finalize(int release_caches);
+
+ //! Perform deferred deallocations pending for the calling thread heap
+ RPMALLOC_EXPORT void
+ rpmalloc_thread_collect(void);
+
+ //! Query if allocator is initialized for calling thread
+ RPMALLOC_EXPORT int
+ rpmalloc_is_thread_initialized(void);
+
+ //! Get per-thread statistics
+ RPMALLOC_EXPORT void
+ rpmalloc_thread_statistics(rpmalloc_thread_statistics_t* stats);
+
+ //! Get global statistics
+ RPMALLOC_EXPORT void
+ rpmalloc_global_statistics(rpmalloc_global_statistics_t* stats);
+
+ //! Dump all statistics in human readable format to file (should be a FILE*)
+ RPMALLOC_EXPORT void
+ rpmalloc_dump_statistics(void* file);
+
+ //! Allocate a memory block of at least the given size
+ RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+ rpmalloc(size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(1);
+
+ //! Free the given memory block
+ RPMALLOC_EXPORT void
+ rpfree(void* ptr);
+
+ //! Allocate a memory block of at least the given size and zero initialize it
+ RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+ rpcalloc(size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(1, 2);
+
+ //! Reallocate the given block to at least the given size
+ RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+ rprealloc(void* ptr, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2);
+
+ //! Reallocate the given block to at least the given size and alignment,
+ // with optional control flags (see RPMALLOC_NO_PRESERVE).
+ // Alignment must be a power of two and a multiple of sizeof(void*),
+ // and should ideally be less than memory page size. A caveat of rpmalloc
+ // internals is that this must also be strictly less than the span size (default 64KiB)
+ RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+ rpaligned_realloc(void* ptr, size_t alignment, size_t size, size_t oldsize, unsigned int flags) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(3);
+
+ //! Allocate a memory block of at least the given size and alignment.
+ // Alignment must be a power of two and a multiple of sizeof(void*),
+ // and should ideally be less than memory page size. A caveat of rpmalloc
+ // internals is that this must also be strictly less than the span size (default 64KiB)
+ RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+ rpaligned_alloc(size_t alignment, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2);
+
+ //! Allocate a memory block of at least the given size and alignment, and zero initialize it.
+ // Alignment must be a power of two and a multiple of sizeof(void*),
+ // and should ideally be less than memory page size. A caveat of rpmalloc
+ // internals is that this must also be strictly less than the span size (default 64KiB)
+ RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+ rpaligned_calloc(size_t alignment, size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(2, 3);
+
+ //! Allocate a memory block of at least the given size and alignment.
+ // Alignment must be a power of two and a multiple of sizeof(void*),
+ // and should ideally be less than memory page size. A caveat of rpmalloc
+ // internals is that this must also be strictly less than the span size (default 64KiB)
+ RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+ rpmemalign(size_t alignment, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2);
+
+ //! Allocate a memory block of at least the given size and alignment.
+ // Alignment must be a power of two and a multiple of sizeof(void*),
+ // and should ideally be less than memory page size. A caveat of rpmalloc
+ // internals is that this must also be strictly less than the span size (default 64KiB)
+ RPMALLOC_EXPORT int
+ rpposix_memalign(void** memptr, size_t alignment, size_t size);
+
+ //! Query the usable size of the given memory block (from given pointer to the end of block)
+ RPMALLOC_EXPORT size_t
+ rpmalloc_usable_size(void* ptr);
+
+ //! Dummy empty function for forcing linker symbol inclusion
+ RPMALLOC_EXPORT void
+ rpmalloc_linker_reference(void);
#if RPMALLOC_FIRST_CLASS_HEAPS
-//! Heap type
-typedef struct heap_t rpmalloc_heap_t;
-
-//! Acquire a new heap. Will reuse existing released heaps or allocate memory for a new heap
-// if none available. Heap API is implemented with the strict assumption that only one single
-// thread will call heap functions for a given heap at any given time, no functions are thread safe.
-RPMALLOC_EXPORT rpmalloc_heap_t*
-rpmalloc_heap_acquire(void);
-
-//! Release a heap (does NOT free the memory allocated by the heap, use rpmalloc_heap_free_all before destroying the heap).
-// Releasing a heap will enable it to be reused by other threads. Safe to pass a null pointer.
-RPMALLOC_EXPORT void
-rpmalloc_heap_release(rpmalloc_heap_t* heap);
-
-//! Allocate a memory block of at least the given size using the given heap.
-RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
-rpmalloc_heap_alloc(rpmalloc_heap_t* heap, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2);
-
-//! Allocate a memory block of at least the given size using the given heap. The returned
-// block will have the requested alignment. Alignment must be a power of two and a multiple of sizeof(void*),
-// and should ideally be less than memory page size. A caveat of rpmalloc
-// internals is that this must also be strictly less than the span size (default 64KiB).
-RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
-rpmalloc_heap_aligned_alloc(rpmalloc_heap_t* heap, size_t alignment, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(3);
-
-//! Allocate a memory block of at least the given size using the given heap and zero initialize it.
-RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
-rpmalloc_heap_calloc(rpmalloc_heap_t* heap, size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(2, 3);
-
-//! Allocate a memory block of at least the given size using the given heap and zero initialize it. The returned
-// block will have the requested alignment. Alignment must either be zero, or a power of two and a multiple of sizeof(void*),
-// and should ideally be less than memory page size. A caveat of rpmalloc
-// internals is that this must also be strictly less than the span size (default 64KiB).
-RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
-rpmalloc_heap_aligned_calloc(rpmalloc_heap_t* heap, size_t alignment, size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(2, 3);
-
-//! Reallocate the given block to at least the given size. The memory block MUST be allocated
-// by the same heap given to this function.
-RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
-rpmalloc_heap_realloc(rpmalloc_heap_t* heap, void* ptr, size_t size, unsigned int flags) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(3);
-
-//! Reallocate the given block to at least the given size. The memory block MUST be allocated
-// by the same heap given to this function. The returned block will have the requested alignment.
-// Alignment must be either zero, or a power of two and a multiple of sizeof(void*), and should ideally be
-// less than memory page size. A caveat of rpmalloc internals is that this must also be strictly less than
-// the span size (default 64KiB).
-RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
-rpmalloc_heap_aligned_realloc(rpmalloc_heap_t* heap, void* ptr, size_t alignment, size_t size, unsigned int flags) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(4);
-
-//! Free the given memory block from the given heap. The memory block MUST be allocated
-// by the same heap given to this function.
-RPMALLOC_EXPORT void
-rpmalloc_heap_free(rpmalloc_heap_t* heap, void* ptr);
-
-//! Free all memory allocated by the heap
-RPMALLOC_EXPORT void
-rpmalloc_heap_free_all(rpmalloc_heap_t* heap);
-
-//! Set the given heap as the current heap for the calling thread. A heap MUST only be current heap
-// for a single thread, a heap can never be shared between multiple threads. The previous
-// current heap for the calling thread is released to be reused by other threads.
-RPMALLOC_EXPORT void
-rpmalloc_heap_thread_set_current(rpmalloc_heap_t* heap);
+ //! Heap type
+ typedef struct heap_t rpmalloc_heap_t;
+
+ //! Acquire a new heap. Will reuse existing released heaps or allocate memory for a new heap
+ // if none available. Heap API is implemented with the strict assumption that only one single
+ // thread will call heap functions for a given heap at any given time, no functions are thread safe.
+ RPMALLOC_EXPORT rpmalloc_heap_t*
+ rpmalloc_heap_acquire(void);
+
+ //! Release a heap (does NOT free the memory allocated by the heap, use rpmalloc_heap_free_all before destroying the heap).
+ // Releasing a heap will enable it to be reused by other threads. Safe to pass a null pointer.
+ RPMALLOC_EXPORT void
+ rpmalloc_heap_release(rpmalloc_heap_t* heap);
+
+ //! Allocate a memory block of at least the given size using the given heap.
+ RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+ rpmalloc_heap_alloc(rpmalloc_heap_t* heap, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2);
+
+ //! Allocate a memory block of at least the given size using the given heap. The returned
+ // block will have the requested alignment. Alignment must be a power of two and a multiple of sizeof(void*),
+ // and should ideally be less than memory page size. A caveat of rpmalloc
+ // internals is that this must also be strictly less than the span size (default 64KiB).
+ RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+ rpmalloc_heap_aligned_alloc(rpmalloc_heap_t* heap, size_t alignment, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(3);
+
+ //! Allocate a memory block of at least the given size using the given heap and zero initialize it.
+ RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+ rpmalloc_heap_calloc(rpmalloc_heap_t* heap, size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(2, 3);
+
+ //! Allocate a memory block of at least the given size using the given heap and zero initialize it. The returned
+ // block will have the requested alignment. Alignment must either be zero, or a power of two and a multiple of sizeof(void*),
+ // and should ideally be less than memory page size. A caveat of rpmalloc
+ // internals is that this must also be strictly less than the span size (default 64KiB).
+ RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+ rpmalloc_heap_aligned_calloc(rpmalloc_heap_t* heap, size_t alignment, size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(2, 3);
+
+ //! Reallocate the given block to at least the given size. The memory block MUST be allocated
+ // by the same heap given to this function.
+ RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+ rpmalloc_heap_realloc(rpmalloc_heap_t* heap, void* ptr, size_t size, unsigned int flags) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(3);
+
+ //! Reallocate the given block to at least the given size. The memory block MUST be allocated
+ // by the same heap given to this function. The returned block will have the requested alignment.
+ // Alignment must be either zero, or a power of two and a multiple of sizeof(void*), and should ideally be
+ // less than memory page size. A caveat of rpmalloc internals is that this must also be strictly less than
+ // the span size (default 64KiB).
+ RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+ rpmalloc_heap_aligned_realloc(rpmalloc_heap_t* heap, void* ptr, size_t alignment, size_t size, unsigned int flags) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(4);
+
+ //! Free the given memory block from the given heap. The memory block MUST be allocated
+ // by the same heap given to this function.
+ RPMALLOC_EXPORT void
+ rpmalloc_heap_free(rpmalloc_heap_t* heap, void* ptr);
+
+ //! Free all memory allocated by the heap
+ RPMALLOC_EXPORT void
+ rpmalloc_heap_free_all(rpmalloc_heap_t* heap);
+
+ //! Set the given heap as the current heap for the calling thread. A heap MUST only be current heap
+ // for a single thread, a heap can never be shared between multiple threads. The previous
+ // current heap for the calling thread is released to be reused by other threads.
+ RPMALLOC_EXPORT void
+ rpmalloc_heap_thread_set_current(rpmalloc_heap_t* heap);
#endif