#include #include #include "malunal/allocators.h" #include "malunal/assert.h" #if MALUNAL_PLATFORM_LINUX # include # include #elif MALUNAL_PLATFORM_WIN32 # include #endif /* Platform headers */ allocator_acquire_res_t allocator_acquire(allocator_acquire_req_t request) { if (request.allocator == NULL_ADDRESS) return (allocator_acquire_res_t) { .threw = 1, .exception = ALLOCATOR_EXCEPTION_NULL_ALLOCATOR }; return request.allocator->vtable.acquire != NULL_ADDRESS ? request.allocator->vtable.acquire(request) : (allocator_acquire_res_t) { .threw = 0, .address = NULL_ADDRESS }; } allocator_acquire_res_t allocator_reacquire(allocator_reacquire_req_t request) { if (request.allocator == NULL_ADDRESS) return (allocator_acquire_res_t) { .threw = 1, .exception = ALLOCATOR_EXCEPTION_NULL_ALLOCATOR }; return request.allocator->vtable.reacquire != NULL_ADDRESS ? request.allocator->vtable.reacquire(request) : (allocator_acquire_res_t) { .threw = 0, .address = NULL_ADDRESS }; } allocator_exception_t allocator_release(allocator_release_req_t request) { if (request.allocator == NULL_ADDRESS) return ALLOCATOR_EXCEPTION_NULL_ALLOCATOR; return request.allocator->vtable.release != NULL_ADDRESS ? request.allocator->vtable.release(request) : ALLOCATOR_EXCEPTION_SUCCESS; } malunal_size_t align_to( malunal_size_t size, malunal_size_t alignment ) { return (size + alignment - 1) & ~(alignment - 1); } malunal_size_t align_to_page(malunal_size_t size) { return align_to(size, platform_page_size()); } static malunal_size_t g_platform_page_size = 0; malunal_size_t platform_page_size() { if (g_platform_page_size != 0) return g_platform_page_size; #if MALUNAL_PLATFORM_LINUX g_platform_page_size = sysconf(_SC_PAGESIZE); #elif MALUNAL_PLATFORM_WIN32 SYSTEM_INFO si; GetSystemInfo(&si); g_platform_page_size = si.dwPageSize; #endif return g_platform_page_size; } static allocator_acquire_res_t libc_acquire(allocator_acquire_req_t request); static allocator_acquire_res_t libc_reacquire(allocator_reacquire_req_t request); static allocator_exception_t libc_release(allocator_release_req_t request); static allocator_acquire_res_t libc_acquire(allocator_acquire_req_t request) { allocator_acquire_res_t result; malunal_mptr_t addr = malloc(request.size); if (addr == NULL_ADDRESS) { return (allocator_acquire_res_t) { .threw = 1, .exception = ALLOCATOR_EXCEPTION_OUT_OF_MEMORY }; } request.allocator->allocated += request.size; request.allocator->reserved += request.size; request.allocator->acquires += 1; return (allocator_acquire_res_t) { .threw = 0, .address = addr }; } static allocator_acquire_res_t libc_reacquire(allocator_reacquire_req_t request) { allocator_acquire_res_t result = libc_acquire((allocator_acquire_req_t) { .allocator = request.allocator, .size = request.newsz }); if (result.threw) return result; result.address = memcpy( result.address, request.prev, request.oldsz ); libc_release((allocator_release_req_t) { .allocator = request.allocator, .address = request.prev, .size = request.oldsz }); return result; } static allocator_exception_t libc_release(allocator_release_req_t request) { free(request.address); request.allocator->allocated -= request.size; request.allocator->reserved -= request.size; request.allocator->releases += 1; return ALLOCATOR_EXCEPTION_SUCCESS; } allocator_t libc_allocator() { return (allocator_t) { .vtable = { .acquire = &libc_acquire, .reacquire = &libc_reacquire, .release = &libc_release }, .context = NULL_ADDRESS }; } allocator_t platform_allocator() { #if MALUNAL_PLATFORM_LINUX return linux_allocator(); #elif MALUNAL_PLATFORM_WIN32 return win32_allocator(); #endif /* Platform specific allocators */ } #if MALUNAL_PLATFORM_LINUX static allocator_acquire_res_t linux_acquire(allocator_acquire_req_t request); static allocator_acquire_res_t linux_reacquire(allocator_reacquire_req_t request); static allocator_exception_t linux_release(allocator_release_req_t request); static allocator_acquire_res_t linux_acquire(allocator_acquire_req_t request) { const malunal_int32_t memops = PROT_READ | PROT_WRITE; const malunal_int32_t memprms = MAP_PRIVATE | MAP_ANONYMOUS; allocator_acquire_res_t result; // TODO: malunal_size_t size = request.size; malunal_mptr_t ptr = mmap(0, size, memops, memprms, -1, 0); if (ptr == MAP_FAILED || ptr == NULL_ADDRESS) { result = (allocator_acquire_res_t) { .threw = 1, .exception = ALLOCATOR_EXCEPTION_OUT_OF_MEMORY }; } else { result = (allocator_acquire_res_t) { .threw = 0, .address = ptr }; } return result; } static allocator_acquire_res_t linux_reacquire(allocator_reacquire_req_t request) { allocator_acquire_res_t result = linux_acquire((allocator_acquire_req_t) { .allocator = request.allocator, .size = request.newsz }); if (result.threw) return result; result.address = memcpy( result.address, request.prev, request.oldsz ); linux_release((allocator_release_req_t) { .allocator = request.allocator, .address = request.prev, .size = request.oldsz }); return result; } static allocator_exception_t linux_release(allocator_release_req_t request) { munmap(request.address, request.size); return ALLOCATOR_EXCEPTION_SUCCESS; } allocator_t linux_allocator() { return (allocator_t) { .vtable = { .acquire = &linux_acquire, .reacquire = &linux_reacquire, .release = &linux_release }, .context = NULL_ADDRESS }; } #elif MALUNAL_PLATFORM_WIN32 static allocator_acquire_res_t win32_acquire(allocator_acquire_req_t request); static allocator_acquire_res_t win32_reacquire(allocator_reacquire_req_t request); static allocator_exception_t win32_release(allocator_release_req_t request); static allocator_acquire_res_t win32_acquire(allocator_acquire_req_t request) { const malunal_int32_t memops = MEM_COMMIT | MEM_RESERVE; const malunal_int32_t pageops = PAGE_READWRITE; malunal_mptr_t addr = VirtualAlloc( NULL_ADDRESS, request.size, memops, pageops ); if (addr == NULL_ADDRESS) { result = (allocator_acquire_res_t) { .threw = 1, .exception = ALLOCATOR_EXCEPTION_OUT_OF_MEMORY }; } else { result = (allocator_acquire_res_t) { .threw = 0, .address = addr }; } return result; } static allocator_acquire_res_t win32_reacquire(allocator_reacquire_req_t request) { allocator_acquire_res_t result = win32_acquire((allocator_acquire_req_t) { .allocator = request.allocator, .size = request.newsz }); if (result.threw) return result; result.address = memcpy( result.address, request.prev, request.oldsz ); win32_release((allocator_release_req_t) { .allocator = request.allocator, .address = request.prev, .size = request.oldsz }); return result; } static allocator_exception_t win32_release(allocator_release_req_t request) { VirtualFree( request.address, request.size, MEM_RELEASE ); return ALLOCATOR_EXCEPTION_SUCCESS; } allocator_t win32_allocator() { return (allocator_t) { .vtable = { .acquire = &win32_acquire, .reacquire = &win32_reacquire, .release = &win32_release }, .context = NULL_ADDRESS }; } #endif /* Platform specific allocators */