opuntiaOS - an operating system targeting x86 and ARMv7
at master 4.6 kB view raw
1#include "malloc.h" 2#include <stdbool.h> 3#include <stdint.h> 4#include <string.h> 5#include <sys/mman.h> 6 7#define ALIGNMENT (4) 8#define DEVIDE_SPACE_BOUNDARY (32) 9 10static malloc_header_t* memory[MALLOC_MAX_ALLOCATED_BLOCKS]; 11static size_t allocated_blocks = 0; 12 13static int _alloc_new_block(size_t sz); 14 15static int _alloc_new_block(size_t sz) 16{ 17 sz += sizeof(malloc_header_t); 18 19 // this will reduce system calls for the small memory allocations 20 size_t allocated_sz = sz > MALLOC_DEFAULT_BLOCK_SIZE ? sz : MALLOC_DEFAULT_BLOCK_SIZE; 21 22 int ret = (int)mmap(NULL, allocated_sz, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); 23 if (ret < 0) { 24 return -1; 25 } 26 memory[allocated_blocks] = (void*)ret; // allocating a new block of memory 27 memory[allocated_blocks]->flags = 0; 28 memory[allocated_blocks]->next = 0; 29 memory[allocated_blocks]->prev = 0; 30 memory[allocated_blocks]->size = allocated_sz - sizeof(malloc_header_t); 31 32 allocated_blocks++; 33 return 0; 34} 35 36static inline char _malloc_need_to_divide_space(malloc_header_t* space, size_t alloc_size) 37{ 38 return alloc_size + DEVIDE_SPACE_BOUNDARY <= space->size; 39} 40 41static inline char _malloc_can_fit_allocation(malloc_header_t* space, size_t alloc_size) 42{ 43 uint32_t add[] = { 0, sizeof(malloc_header_t) }; 44 return space->size >= (alloc_size + add[_malloc_need_to_divide_space(space, alloc_size)]); 45} 46 47void* malloc(size_t sz) 48{ 49 if (!sz) { 50 return NULL; 51 } 52 sz += (ALIGNMENT - 1); 53 sz &= ~(uint32_t)(ALIGNMENT - 1); 54 55 void* res = slab_alloc(sz); 56 if (res) { 57 return res; 58 } 59 60 /* iterating over allocated by mmap blocks 61 and finding a first fit memory chunk */ 62 malloc_header_t* first_fit = 0; 63 for (size_t i = 0; i < allocated_blocks; i++) { 64 malloc_header_t* cur_block = memory[i]; 65 while (cur_block->next && !(block_is_free(cur_block) && _malloc_can_fit_allocation(cur_block, sz))) { 66 cur_block = cur_block->next; 67 } 68 if (block_is_free(cur_block) && _malloc_can_fit_allocation(cur_block, sz)) { 69 first_fit = cur_block; 70 break; 71 } 72 } 73 74 if (!first_fit) { 75 int err = _alloc_new_block(sz); 76 if (err) { 77 return NULL; 78 } 79 first_fit = memory[allocated_blocks - 1]; 80 } 81 82 malloc_header_t* copy_next = first_fit->next; 83 size_t copy_size = first_fit->size; 84 85 first_fit->flags |= FLAG_ALLOCATED; 86 if (_malloc_need_to_divide_space(first_fit, sz)) { 87 first_fit->size = sz; 88 first_fit->next = (malloc_header_t*)((uintptr_t)first_fit + sz + sizeof(malloc_header_t)); 89 90 // adjust the firstfit chunk 91 first_fit->next->flags = 0; 92 first_fit->next->size = copy_size - sz - sizeof(malloc_header_t); 93 first_fit->next->next = copy_next; 94 first_fit->next->prev = first_fit; 95 96 if (first_fit->next->next) { 97 first_fit->next->next->prev = first_fit->next; 98 } 99 } 100 101 return (void*)&((malloc_header_t*)first_fit)[1]; 102} 103 104void free(void* mem) 105{ 106 if (!mem) { 107 return; 108 } 109 110 malloc_header_t* mem_header = &((malloc_header_t*)mem)[-1]; 111 112 if (block_is_slab(mem_header)) { 113 return slab_free(mem_header); 114 } 115 116 block_rem_flags(mem_header, FLAG_ALLOCATED); 117 while (mem_header->prev && block_is_free(mem_header->prev)) { 118 mem_header = mem_header->prev; 119 } 120 121 // Trying to glue the freed chunk with its neighbours. 122 while (mem_header->next && block_is_free(mem_header->next)) { 123 mem_header->size += mem_header->next->size + sizeof(malloc_header_t); 124 125 if (mem_header->next->next) { 126 mem_header->next->next->prev = mem_header; 127 } 128 mem_header->next = mem_header->next->next; 129 } 130} 131 132void* calloc(size_t num, size_t size) 133{ 134 void* mem = malloc(num * size); 135 if (!mem) { 136 return NULL; 137 } 138 139 memset(mem, 0, num * size); 140 return mem; 141} 142 143void* realloc(void* ptr, size_t new_size) 144{ 145 if (!ptr) { 146 return malloc(new_size); 147 } 148 149 size_t old_size = ((malloc_header_t*)ptr)[-1].size; 150 if (old_size == new_size) { 151 return ptr; 152 } 153 154 uint8_t* new_area = malloc(new_size); 155 if (!new_area) { 156 return NULL; 157 } 158 159 memcpy(new_area, ptr, new_size < old_size ? new_size : old_size); 160 free(ptr); 161 162 return new_area; 163} 164 165void _malloc_init() 166{ 167 _slab_init(); 168}