diff --git a/Src/Hallocy/Allocator.c b/Src/Hallocy/Allocator.c index ba86aa7..6ecf751 100644 --- a/Src/Hallocy/Allocator.c +++ b/Src/Hallocy/Allocator.c @@ -25,11 +25,20 @@ #if defined(_WIN32) #include +static const INIT_ONCE HALLOCY_INIT_ONCE = INIT_ONCE_STATIC_INIT; + static HANDLE hallocy_heap = NULL; +static CRITICAL_SECTION hallocy_critical_section; #elif defined(__linux__) #include #include #include +#include + +static const int HALLOCY_FUTEX_WAKE = 0; +static const int HALLOCY_FUTEX_WAIT = 1; + +static int hallocy_futex_address = 0; #endif typedef struct HallocyMemoryHeader { @@ -37,12 +46,27 @@ typedef struct HallocyMemoryHeader { struct HallocyMemoryHeader *next; } HallocyMemoryHeader; +static size_t hallocy_medium_memory_freed = 0; +static size_t hallocy_medium_memory_allocated = 0; +static HallocyMemoryHeader *hallocy_medium_memory_bin = NULL; + static _Thread_local size_t hallocy_small_memory_freed = 0; static _Thread_local size_t hallocy_small_memory_allocated = 0; static _Thread_local HallocyMemoryHeader *hallocy_small_memory_bin = NULL; static size_t page_size = 0; static size_t hallocy_small_allocation_size = 0; +static size_t hallocy_medium_allocation_size = 0; + +#if defined(_WIN32) +static BOOL CALLBACK hallocy_initialize_mutex(PINIT_ONCE init_once, PVOID parameter, PVOID *context) { + (void)init_once; + (void)parameter; + (void)context; + + return InitializeCriticalSectionEx(&hallocy_critical_section, 0x00000400, 0); +} +#endif void *hallocy_malloc(size_t size) { if (page_size == 0) { @@ -56,6 +80,7 @@ void *hallocy_malloc(size_t size) { #endif hallocy_small_allocation_size = page_size; + hallocy_medium_allocation_size = page_size * 10; } size_t aligned_size = page_size * (((size + sizeof(HallocyMemoryHeader)) / page_size) + 1); @@ -99,6 +124,72 @@ void *hallocy_malloc(size_t size) { #endif hallocy_small_memory_allocated += aligned_size; + } else if (aligned_size <= hallocy_medium_allocation_size) { + #if defined(_WIN32) + InitOnceExecuteOnce(&HALLOCY_INIT_ONCE, hallocy_initialize_mutex, NULL, NULL); + EnterCriticalSection(&hallocy_critical_section); + #elif defined(__linux__) + bool locked = false; + while (!locked) { + if (__sync_bool_compare_and_swap(&hallocy_futex_address, 0, 1)) { + locked = true; + } else { + syscall(SYS_futex, &hallocy_futex_address, HALLOCY_FUTEX_WAIT, 1, NULL, NULL, 0); + } + } + #endif + + HallocyMemoryHeader *previous_header = NULL; + memory_pointer = hallocy_medium_memory_bin; + while (memory_pointer != NULL) { + if (memory_pointer->size >= aligned_size) { + hallocy_medium_memory_allocated += memory_pointer->size; + hallocy_medium_memory_freed -= memory_pointer->size; + + if (previous_header == NULL) { + hallocy_medium_memory_bin = hallocy_medium_memory_bin->next; + } else { + previous_header->next = memory_pointer->next; + } + + #if defined(_WIN32) + LeaveCriticalSection(&hallocy_critical_section); + #elif defined(__linux__) + hallocy_futex_address = 0; + syscall(SYS_futex, &hallocy_futex_address, HALLOCY_FUTEX_WAKE, 1, NULL, NULL, 0); + #endif + + memory_pointer->next = NULL; + return (void*)(memory_pointer + 1); + } + + previous_header = memory_pointer; + memory_pointer = memory_pointer->next; + } + + #if defined(_WIN32) + if (hallocy_heap == NULL) { + hallocy_heap = GetProcessHeap(); + } + + memory_pointer = HeapAlloc(hallocy_heap, 0, aligned_size); + if (memory_pointer == NULL) { + return NULL; + } + + hallocy_medium_allocation_size += aligned_size; + LeaveCriticalSection(&hallocy_critical_section); + #elif defined(__linux__) + memory_pointer = mmap(NULL, aligned_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (memory_pointer == MAP_FAILED) { + return NULL; + } + + hallocy_medium_allocation_size += aligned_size; + + hallocy_futex_address = 0; + syscall(SYS_futex, &hallocy_futex_address, HALLOCY_FUTEX_WAKE, 1, NULL, NULL, 0); + #endif } else { #if defined(_WIN32) memory_pointer = (HallocyMemoryHeader*)VirtualAlloc(NULL, aligned_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); @@ -131,7 +222,7 @@ HallocyError hallocy_free(void *pointer) { hallocy_small_memory_allocated -= memory_header->size; hallocy_small_memory_freed += memory_header->size; - if (hallocy_small_memory_allocated == 0 && hallocy_small_memory_freed > hallocy_small_allocation_size * 10) { + if (hallocy_small_memory_allocated == 0 && hallocy_small_memory_freed > hallocy_medium_allocation_size) { HallocyMemoryHeader *previous_header = NULL; HallocyMemoryHeader *current_header = hallocy_small_memory_bin; while (current_header != NULL) { @@ -180,6 +271,82 @@ HallocyError hallocy_free(void *pointer) { hallocy_small_memory_allocated = 0; hallocy_small_memory_freed = 0; } + } else if (memory_header->size <= hallocy_medium_allocation_size) { + #if defined(_WIN32) + InitOnceExecuteOnce(&HALLOCY_INIT_ONCE, hallocy_initialize_mutex, NULL, NULL); + EnterCriticalSection(&hallocy_critical_section); + #elif defined(__linux__) + bool locked = false; + while (!locked) { + if (__sync_bool_compare_and_swap(&hallocy_futex_address, 0, 1)) { + locked = true; + } else { + syscall(SYS_futex, &hallocy_futex_address, HALLOCY_FUTEX_WAIT, 1, NULL, NULL, 0); + } + } + #endif + + memory_header->next = hallocy_medium_memory_bin; + hallocy_medium_memory_bin = memory_header; + + hallocy_medium_memory_allocated -= memory_header->size; + hallocy_medium_memory_freed += memory_header->size; + if (hallocy_medium_memory_allocated == 0 && hallocy_medium_memory_freed > hallocy_medium_allocation_size) { + HallocyMemoryHeader *previous_header = NULL; + HallocyMemoryHeader *current_header = hallocy_medium_memory_bin; + while (current_header != NULL) { + previous_header = current_header; + current_header = current_header->next; + + #if defined(_WIN32) + bool result = HeapFree(hallocy_heap, 0, previous_header); + if (result == false) { + DWORD error = GetLastError(); + switch (error) { + case ERROR_INVALID_PARAMETER: + return HALLOCY_ERROR_INVALID_PARAM; + + case ERROR_NOT_ENOUGH_MEMORY: + return HALLOCY_ERROR_OUT_OF_MEMORY; + + case ERROR_INVALID_HANDLE: + return HALLOCY_ERROR_INVALID_POINTER; + + default: + return HALLOCY_ERROR_UNKNOWN; + } + } + #elif defined(__linux__) + int result = munmap(previous_header, previous_header->size); + if (result == -1) { + switch (errno) { + case EINVAL: + return HALLOCY_ERROR_INVALID_PARAM; + + case ENOMEM: + return HALLOCY_ERROR_OUT_OF_MEMORY; + + case EFAULT: + return HALLOCY_ERROR_INVALID_POINTER; + + default: + return HALLOCY_ERROR_UNKNOWN; + } + } + #endif + } + + hallocy_medium_memory_bin = NULL; + hallocy_medium_memory_allocated = 0; + hallocy_medium_memory_freed = 0; + } + + #if defined(_WIN32) + LeaveCriticalSection(&hallocy_critical_section); + #elif defined(__linux__) + hallocy_futex_address = 0; + syscall(SYS_futex, &hallocy_futex_address, HALLOCY_FUTEX_WAKE, 1, NULL, NULL, 0); + #endif } else { #if defined(_WIN32) bool result = VirtualFree(memory_header, 0, MEM_RELEASE); diff --git a/Src/Main.c b/Src/Main.c index 3b99def..8fc9e75 100644 --- a/Src/Main.c +++ b/Src/Main.c @@ -2,7 +2,7 @@ #include int main() { - char *memory = (char *)hallocy_malloc(3); + char *memory = (char *)hallocy_malloc(12288); if (memory == NULL) { printf("Failed it allocate memory!"); return -1;