PatchworkOS
Loading...
Searching...
No Matches
heap.c
Go to the documentation of this file.
1#include "heap.h"
2
3#include <stdio.h>
4#include <stdlib.h>
5#include <string.h>
6#include <sys/bitmap.h>
7#include <sys/io.h>
8#include <sys/math.h>
9#include <sys/proc.h>
10#include <threads.h>
11
12#ifdef __KERNEL__
13#include <kernel/log/panic.h>
14#include <kernel/mem/vmm.h>
15#include <kernel/sync/lock.h>
16static lock_t mutex;
17
18void* _heap_map_memory(uint64_t size)
19{
21 if (addr == NULL)
22 {
23 return NULL;
24 }
25 memset(addr, 0, size);
26
27 return addr;
28}
29
30void _heap_unmap_memory(void* addr, uint64_t size)
31{
32 vmm_unmap(NULL, addr, size);
33}
34#else // ndef __KERNEL__
35static mtx_t mutex;
36
37static fd_t zeroDev = ERR;
38
40{
41 void* addr = mmap(zeroDev, NULL, size, PROT_READ | PROT_WRITE);
42 if (addr == NULL)
43 {
44 return NULL;
45 }
46
47 return addr;
48}
49
50void _heap_unmap_memory(void* addr, uint64_t size)
51{
52 munmap(addr, size);
53}
54#endif // ndef __KERNEL__
55
57static bitmap_t freeBitmap = {0};
59
61
62void _heap_init(void)
63{
64#ifdef __KERNEL__
66#else
68 zeroDev = open("/dev/zero");
69 if (zeroDev == ERR)
70 {
71 abort();
72 }
73#endif
74 for (uint64_t i = 0; i < _HEAP_NUM_BINS; i++)
75 {
77 }
79}
80
81void _heap_acquire(void)
82{
83#ifdef __KERNEL__
85#else
87#endif
88}
89
90void _heap_release(void)
91{
92#ifdef __KERNEL__
94#else
96#endif
97}
98
100{
102 {
103 return ERR;
104 }
105
106 if (size < _HEAP_ALIGNMENT)
107 {
108 return 0;
109 }
110
111 return (size / _HEAP_ALIGNMENT) - 1;
112}
113
115{
116 if (minSize == 0)
117 {
118 return NULL;
119 }
120
121 uint64_t totalSize = MAX(sizeof(_heap_header_t) + minSize, PAGE_SIZE);
123 uint64_t alignedTotalSize = pageAmount * PAGE_SIZE;
124
125 _heap_header_t* newBlock = _heap_map_memory(alignedTotalSize);
126 if (newBlock == NULL)
127 {
128 return NULL;
129 }
130 newBlock->magic = _HEAP_HEADER_MAGIC;
131 newBlock->flags = _HEAP_ZEROED;
132 newBlock->size = alignedTotalSize - sizeof(_heap_header_t);
133 list_entry_init(&newBlock->freeEntry);
134 list_entry_init(&newBlock->listEntry);
135
137 while (last != NULL && (uintptr_t)last > (uintptr_t)newBlock)
138 {
139 last = CONTAINER_OF_SAFE(last->listEntry.prev, _heap_header_t, listEntry);
140 }
141
142 if (last == NULL)
143 {
144 list_push(&_heapList, &newBlock->listEntry);
145 }
146 else
147 {
148 list_append(&_heapList, &last->listEntry, &newBlock->listEntry);
149 }
150
151 return newBlock;
152}
153
155{
156 assert(newSize % _HEAP_ALIGNMENT == 0);
157 uint64_t originalTotalSize = sizeof(_heap_header_t) + block->size;
158 uint64_t newTotalSize = sizeof(_heap_header_t) + newSize;
159
160 _heap_header_t* remainder = (_heap_header_t*)((uintptr_t)block + newTotalSize);
162 remainder->flags = block->flags & _HEAP_ZEROED;
163 remainder->size = originalTotalSize - newTotalSize - sizeof(_heap_header_t);
164 list_entry_init(&remainder->freeEntry);
165 list_entry_init(&remainder->listEntry);
166
167 block->size = newSize;
168
169 list_append(&_heapList, &block->listEntry, &remainder->listEntry);
170
172}
173
175{
176 uint64_t binIndex = _heap_get_bin_index(block->size);
177 if (binIndex == ERR)
178 {
179 return;
180 }
181 list_push(&freeLists[binIndex], &block->freeEntry);
182 bitmap_set(&freeBitmap, binIndex);
183}
184
186{
187 uint64_t binIndex = _heap_get_bin_index(block->size);
188 if (binIndex == ERR)
189 {
190 return;
191 }
192 list_remove(&freeLists[binIndex], &block->freeEntry);
193 if (list_is_empty(&freeLists[binIndex]))
194 {
195 bitmap_clear(&freeBitmap, binIndex);
196 }
197}
198
200{
201 if (size == 0)
202 {
203 return NULL;
204 }
205
207 {
208 uint64_t totalSize = sizeof(_heap_header_t) + size;
210 uint64_t alignedTotalSize = pageAmount * PAGE_SIZE;
211
212 _heap_header_t* block = _heap_map_memory(alignedTotalSize);
213 if (block == NULL)
214 {
215 return NULL;
216 }
217 block->magic = _HEAP_HEADER_MAGIC;
219 block->size = alignedTotalSize - sizeof(_heap_header_t);
220 list_entry_init(&block->freeEntry);
221 list_entry_init(&block->listEntry);
222
223 return block;
224 }
225
226 size = ROUND_UP(size, _HEAP_ALIGNMENT);
227
228 uint64_t index = _heap_get_bin_index(size);
229 _heap_header_t* suitableBlock = NULL;
230
231 uint64_t freeBinIndex = bitmap_find_first_set(&freeBitmap, index);
232 if (freeBinIndex != freeBitmap.length)
233 {
234 suitableBlock = CONTAINER_OF(list_pop(&freeLists[freeBinIndex]), _heap_header_t, freeEntry);
235 if (list_is_empty(&freeLists[freeBinIndex]))
236 {
237 bitmap_clear(&freeBitmap, freeBinIndex);
238 }
239 }
240
241 if (suitableBlock == NULL)
242 {
243 suitableBlock = _heap_block_new(size);
244 if (suitableBlock == NULL)
245 {
246 return NULL;
247 }
248 }
249
250 suitableBlock->flags |= _HEAP_ALLOCATED;
251 if (suitableBlock->size >= size + sizeof(_heap_header_t) + _HEAP_ALIGNMENT)
252 {
253 _heap_block_split(suitableBlock, size);
254 }
255
256 return suitableBlock;
257}
258
260{
261 if (block->flags & _HEAP_MAPPED)
262 {
264 _heap_unmap_memory(block, sizeof(_heap_header_t) + block->size);
265 return;
266 }
267 else
268 {
270 }
271
272 block->flags &= ~_HEAP_ALLOCATED;
273
276
277 if (next != NULL && !(next->flags & _HEAP_ALLOCATED) && (block->data + block->size == (uint8_t*)next))
278 {
279 uint64_t newSize = block->size + sizeof(_heap_header_t) + next->size;
280 if (newSize <= _HEAP_LARGE_ALLOC_THRESHOLD)
281 {
283 block->size = newSize;
284 block->flags = (block->flags & _HEAP_ZEROED) & (next->flags & _HEAP_ZEROED);
285
286 list_remove(&_heapList, &next->listEntry);
287 }
288 }
289
290 if (prev != NULL && !(prev->flags & _HEAP_ALLOCATED) && (prev->data + prev->size == (uint8_t*)block))
291 {
292 uint64_t newSize = prev->size + sizeof(_heap_header_t) + block->size;
293 if (newSize <= _HEAP_LARGE_ALLOC_THRESHOLD)
294 {
296 prev->size = newSize;
297 prev->flags = (prev->flags & _HEAP_ZEROED) & (block->flags & _HEAP_ZEROED);
298
300
301 block = prev;
302 }
303 }
304
306}
#define assert(expression)
Definition assert.h:29
@ PML_PRESENT
@ PML_WRITE
@ PML_GLOBAL
uint64_t vmm_unmap(space_t *space, void *virtAddr, uint64_t length)
Unmaps virtual memory from a given address space.
Definition vmm.c:339
void * vmm_alloc(space_t *space, void *virtAddr, uint64_t length, pml_flags_t pmlFlags, vmm_alloc_flags_t allocFlags)
Allocates and maps virtual memory in a given address space.
Definition vmm.c:168
@ VMM_ALLOC_NONE
Definition vmm.h:123
static void lock_init(lock_t *lock)
Initializes a lock.
Definition lock.h:80
static void lock_release(lock_t *lock)
Releases a lock.
Definition lock.h:140
static void lock_acquire(lock_t *lock)
Acquires a lock, blocking until it is available.
Definition lock.h:97
#define _HEAP_LARGE_ALLOC_THRESHOLD
Definition heap.h:41
void _heap_acquire(void)
Acquire the heap lock.
Definition heap.c:81
void _heap_add_to_free_list(_heap_header_t *block)
Adds a block to the appropriate free list.
Definition heap.c:174
_heap_header_t * _heap_block_new(uint64_t minSize)
Directly maps a new heap block of at least minSize bytes.
Definition heap.c:114
void _heap_unmap_memory(void *addr, uint64_t size)
Unmaps previously mapped memory.
Definition heap.c:50
#define _HEAP_NUM_BINS
Definition heap.h:46
void _heap_init(void)
Initialize the heap.
Definition heap.c:62
void _heap_free(_heap_header_t *block)
Frees a previously allocated heap block.
Definition heap.c:259
void _heap_block_split(_heap_header_t *block, uint64_t newSize)
Splits a heap block into two blocks, the first of size bytes and the second with the remaining bytes.
Definition heap.c:154
void * _heap_map_memory(uint64_t size)
Directly maps memory of the given size.
Definition heap.c:39
_heap_header_t * _heap_alloc(uint64_t size)
Allocates a block of memory of given size.
Definition heap.c:199
list_t _heapList
A list of all blocks sorted by address.
Definition heap.c:60
void _heap_remove_from_free_list(_heap_header_t *block)
Removes a block from its free list.
Definition heap.c:185
#define _HEAP_HEADER_MAGIC
Definition heap.h:36
void _heap_release(void)
Release the heap lock.
Definition heap.c:90
#define _HEAP_ALIGNMENT
Definition heap.h:31
uint64_t _heap_get_bin_index(uint64_t size)
Get the bin index for a given size.
Definition heap.c:99
@ _HEAP_ALLOCATED
Block is allocated.
Definition heap.h:53
@ _HEAP_MAPPED
Block is not on the heap, but mapped directly, used for large allocations.
Definition heap.h:54
@ _HEAP_ZEROED
Block is zeroed.
Definition heap.h:55
static void bitmap_clear(bitmap_t *map, uint64_t index)
Clear a bit in the bitmap.
Definition bitmap.h:186
static void bitmap_set(bitmap_t *map, uint64_t index)
Set a bit in the bitmap.
Definition bitmap.h:106
static void bitmap_init(bitmap_t *map, void *buffer, uint64_t length)
Initialize a bitmap.
Definition bitmap.h:74
#define BITMAP_BITS_TO_QWORDS(bits)
Convert number of bits to number of qwords.
Definition bitmap.h:34
static uint64_t bitmap_find_first_set(bitmap_t *map, uint64_t startIdx)
Find the first set bit in the bitmap.
Definition bitmap.h:323
fd_t open(const char *path)
System call for opening files.
Definition open.c:9
static list_entry_t * list_last(list_t *list)
Gets the last entry in the list without removing it.
Definition list.h:400
#define LIST_CREATE(name)
Creates a list initializer.
Definition list.h:176
static void list_remove(list_t *list, list_entry_t *entry)
Removes a list entry from its current list.
Definition list.h:317
static void list_push(list_t *list, list_entry_t *entry)
Pushes an entry to the end of the list.
Definition list.h:345
static void list_append(list_t *list, list_entry_t *prev, list_entry_t *entry)
Appends an entry to the list.
Definition list.h:292
static bool list_is_empty(list_t *list)
Checks if a list is empty.
Definition list.h:229
static void list_entry_init(list_entry_t *entry)
Initializes a list entry.
Definition list.h:184
static void list_init(list_t *list)
Initializes a list.
Definition list.h:198
static list_entry_t * list_pop(list_t *list)
Pops the first entry from the list.
Definition list.h:361
#define ROUND_UP(number, multiple)
Definition math.h:19
#define MAX(x, y)
Definition math.h:15
void * mmap(fd_t fd, void *address, uint64_t length, prot_t prot)
System call to map memory from a file.
Definition mmap.c:6
#define PAGE_SIZE
Memory page size.
Definition proc.h:140
uint64_t munmap(void *address, uint64_t length)
System call to unmap mapped memory.
Definition munmap.c:6
#define BYTES_TO_PAGES(amount)
Convert bytes to pages.
Definition proc.h:151
@ PROT_READ
Memory can be read from.
Definition proc.h:172
@ PROT_WRITE
Memory can be written to.
Definition proc.h:173
#define NULL
Pointer error value.
Definition NULL.h:23
#define ERR
Integer error value.
Definition ERR.h:17
#define CONTAINER_OF(ptr, type, member)
Container of macro.
__UINT64_TYPE__ fd_t
A file descriptor.
Definition fd_t.h:12
#define CONTAINER_OF_SAFE(ptr, type, member)
Safe container of macro.
static mtx_t mutex
Definition heap.c:35
static list_t freeLists[_HEAP_NUM_BINS]
Definition heap.c:56
static bitmap_t freeBitmap
Definition heap.c:57
static uint64_t freeBitmapBuffer[BITMAP_BITS_TO_QWORDS(_HEAP_NUM_BINS)]
Definition heap.c:58
static fd_t zeroDev
Definition heap.c:37
double remainder(double x, double y)
static uint64_t pageAmount
Definition pmm.c:42
static atomic_long next
Definition main.c:10
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
__UINT8_TYPE__ uint8_t
Definition stdint.h:11
__UINTPTR_TYPE__ uintptr_t
Definition stdint.h:43
_PUBLIC _NORETURN void abort(void)
Definition abort.c:7
_PUBLIC void * memset(void *s, int c, size_t n)
Definition memset.c:4
uint8_t data[]
Definition heap.h:73
list_entry_t freeEntry
Definition heap.h:71
uint64_t size
Definition heap.h:70
list_entry_t listEntry
Definition heap.h:72
_heap_flags_t flags
Definition heap.h:69
uint32_t magic
Definition heap.h:68
Bitmap structure.
Definition bitmap.h:22
uint64_t length
Definition bitmap.h:24
struct list_entry * next
The next entry in the list.
Definition list.h:40
struct list_entry * prev
The previous entry in the list.
Definition list.h:39
A doubly linked list.
Definition list.h:51
A simple ticket lock implementation.
Definition lock.h:43
_PUBLIC int mtx_lock(mtx_t *mtx)
Definition mtx_lock.c:11
_PUBLIC int mtx_init(mtx_t *mtx, int type)
Definition mtx_init.c:10
_PUBLIC int mtx_unlock(mtx_t *mtx)
Definition mtx_unlock.c:10
@ mtx_plain
Definition threads.h:66