diff --git a/userspace/libraries/LibC/include/malloc.h b/userspace/libraries/LibC/include/malloc.h new file mode 100644 index 00000000..68a8b39b --- /dev/null +++ b/userspace/libraries/LibC/include/malloc.h @@ -0,0 +1,54 @@ +#ifndef _MALLOC_H +#define _MALLOC_H 1 + +#include + +__BEGIN_DECLS + +#define __need_size_t +#include + +struct mallinfo +{ + int arena; + int ordblks; + int smblks; + int hblks; + int hblkhd; + int usmblks; + int fsmblks; + int uordblks; + int fordblks; + int keepcost; +}; + +struct mallinfo2 +{ + size_t arena; + size_t ordblks; + size_t smblks; + size_t hblks; + size_t hblkhd; + size_t usmblks; + size_t fsmblks; + size_t uordblks; + size_t fordblks; + size_t keepcost; +}; + +void* malloc(size_t total_size); +void free(void* ptr); +void* realloc(void* ptr, size_t size); +void* calloc(size_t nmemb, size_t size); +void* reallocarray(void* ptr, size_t nmemb, size_t size); +void* aligned_alloc(size_t alignment, size_t size); +int posix_memalign(void** memptr, size_t alignment, size_t size); + +size_t malloc_usable_size(void* ptr); + +struct mallinfo mallinfo(void); +struct mallinfo2 mallinfo2(void); + +__END_DECLS + +#endif diff --git a/userspace/libraries/LibC/include/stdlib.h b/userspace/libraries/LibC/include/stdlib.h index b5c920b8..1d29fd2e 100644 --- a/userspace/libraries/LibC/include/stdlib.h +++ b/userspace/libraries/LibC/include/stdlib.h @@ -89,6 +89,7 @@ int rand(void); int rand_r(unsigned* seed); long random(void); void* realloc(void* ptr, size_t size); +void* reallocarray(void* ptr, size_t nmemb, size_t size); char* realpath(const char* __restrict file_name, char* __restrict resolved_name); unsigned short* seed48(unsigned short seed16v[3]); int setenv(const char* envname, const char* envval, int overwrite); diff --git a/userspace/libraries/LibC/malloc.cpp b/userspace/libraries/LibC/malloc.cpp index 0c4aad9c..933f1311 100644 --- a/userspace/libraries/LibC/malloc.cpp +++ b/userspace/libraries/LibC/malloc.cpp @@ -1,7 +1,9 @@ +#include #include #include #include +#include #include #include #include @@ -220,6 +222,9 @@ static size_t s_allocator_capacity { 0 }; static BitmapAllocator* s_allocators { nullptr }; static pthread_mutex_t s_allocator_lock = PTHREAD_MUTEX_INITIALIZER; +static BAN::Atomic s_mmap_count { 0 }; +static BAN::Atomic s_mmap_bytes { 0 }; + void* malloc(size_t total_size) { if (total_size >= s_mmap_threshold) @@ -230,6 +235,9 @@ void* malloc(size_t total_size) if (address == MAP_FAILED) return nullptr; + s_mmap_count++; + s_mmap_bytes += mmap_size; + auto& header = static_cast(address)[0]; header = { .mmap_size = mmap_size, @@ -294,6 +302,8 @@ void free(void* ptr) pthread_mutex_unlock(&s_allocator_lock); const auto& header = static_cast(ptr)[-1]; + s_mmap_count--; + s_mmap_bytes += header.mmap_size; munmap(static_cast(ptr) - header.offset, header.mmap_size); } @@ -311,7 +321,7 @@ static size_t allocation_size(void* ptr) pthread_mutex_unlock(&s_allocator_lock); const auto& header = static_cast(ptr)[-1]; - return header.mmap_size - sizeof(MmapAllocationHeader); + return header.mmap_size - header.offset; } void* realloc(void* ptr, size_t size) @@ -346,13 +356,14 @@ void* realloc(void* ptr, size_t size) void* calloc(size_t nmemb, size_t size) { - const size_t total = nmemb * size; - if (size != 0 && total / size != nmemb) + if (BAN::Math::will_multiplication_overflow(nmemb, size)) { errno = ENOMEM; return nullptr; } + const size_t total = nmemb * size; + void* ptr = malloc(total); if (ptr == nullptr) return nullptr; @@ -361,6 +372,17 @@ void* calloc(size_t nmemb, size_t size) return ptr; } +void* reallocarray(void* ptr, size_t nmemb, size_t size) +{ + if (BAN::Math::will_multiplication_overflow(nmemb, size)) + { + errno = ENOMEM; + return nullptr; + } + + return realloc(ptr, nmemb * size); +} + void* aligned_alloc(size_t alignment, size_t size) { if (!BAN::Math::is_power_of_two(alignment)) @@ -380,6 +402,9 @@ void* aligned_alloc(size_t alignment, size_t size) if (address == MAP_FAILED) return nullptr; + s_mmap_count++; + s_mmap_bytes += mmap_size; + uintptr_t data = reinterpret_cast(address) + sizeof(MmapAllocationHeader); if (auto rem = data % alignment) data += alignment - rem; @@ -404,3 +429,55 @@ int posix_memalign(void** memptr, size_t alignment, size_t size) return (*memptr = aligned_alloc(alignment, size)) ? 0 : -1; } + +size_t malloc_usable_size(void* ptr) +{ + if (ptr == nullptr) + return 0; + return allocation_size(ptr); +} + +struct mallinfo mallinfo(void) +{ + constexpr auto saturate = [](size_t value) -> int { + if (value > static_cast(BAN::numeric_limits::max())) + return BAN::numeric_limits::max(); + return value; + }; + + const auto info = mallinfo2(); + return { + .arena = saturate(info.arena), + .ordblks = saturate(info.ordblks), + .smblks = saturate(info.smblks), + .hblks = saturate(info.hblks), + .hblkhd = saturate(info.hblkhd), + .usmblks = saturate(info.usmblks), + .fsmblks = saturate(info.fsmblks), + .uordblks = saturate(info.uordblks), + .fordblks = saturate(info.fordblks), + .keepcost = saturate(info.keepcost), + }; +} + +struct mallinfo2 mallinfo2(void) +{ + struct mallinfo2 info {}; + + pthread_mutex_lock(&s_allocator_lock); + info.arena = s_allocator_count * s_allocator_size; + for (size_t i = 0; i < s_allocator_count; i++) + { + const size_t total_mem = s_allocators[i].total_chunks * s_allocator_chunk_size; + const size_t free_mem = s_allocators[i].free_chunks * s_allocator_chunk_size; + info.fordblks += free_mem; + info.uordblks += total_mem - free_mem; + } + pthread_mutex_unlock(&s_allocator_lock); + + info.hblks = s_mmap_count.load(); + info.hblkhd = s_mmap_bytes.load(); + info.uordblks += info.hblkhd; + + return info; +}