PatchworkOS  966e257
A non-POSIX operating system.
Loading...
Searching...
No Matches
heap.c
Go to the documentation of this file.
1#include "heap.h"
2
3#include <string.h>
4#include <sys/bitmap.h>
5#include <sys/io.h>
6#include <sys/math.h>
7#include <sys/proc.h>
8
9#ifdef _KERNEL_
10#include <kernel/log/panic.h>
11#include <kernel/mem/vmm.h>
12#include <kernel/sync/lock.h>
13static lock_t mutex;
14
15void* _heap_map_memory(uint64_t size)
16{
18 if (addr == NULL)
19 {
20 return NULL;
21 }
22 memset(addr, 0, size);
23
24 return addr;
25}
26
27void _heap_unmap_memory(void* addr, uint64_t size)
28{
29 vmm_unmap(NULL, addr, size);
30}
31#else // ndef _KERNEL_
32#include <stdlib.h>
33#include <threads.h>
34
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
60static bool initialized = false;
61
63
64void _heap_init(void)
65{
66#ifdef _KERNEL_
68#else
70 zeroDev = open("/dev/zero");
71 if (zeroDev == ERR)
72 {
73 abort();
74 }
75#endif
76 for (uint64_t i = 0; i < _HEAP_NUM_BINS; i++)
77 {
79 }
81 initialized = true;
82}
83
84void _heap_acquire(void)
85{
86 if (!initialized)
87 {
88 return;
89 }
90
91#ifdef _KERNEL_
93#else
95#endif
96}
97
98void _heap_release(void)
99{
100 if (!initialized)
101 {
102 return;
103 }
104
105#ifdef _KERNEL_
107#else
109#endif
110}
111
113{
115 {
116 return ERR;
117 }
118
119 if (size < _HEAP_ALIGNMENT)
120 {
121 return 0;
122 }
123
124 return (size / _HEAP_ALIGNMENT) - 1;
125}
126
128{
129 if (minSize == 0)
130 {
131 return NULL;
132 }
133
134 if (!initialized)
135 {
136 return NULL;
137 }
138
139 uint64_t totalSize = MAX(sizeof(_heap_header_t) + minSize, PAGE_SIZE);
141 uint64_t alignedTotalSize = pageAmount * PAGE_SIZE;
142
143 _heap_header_t* newBlock = _heap_map_memory(alignedTotalSize);
144 if (newBlock == NULL)
145 {
146 return NULL;
147 }
148 newBlock->magic = _HEAP_HEADER_MAGIC;
149 newBlock->flags = _HEAP_ZEROED;
150 newBlock->size = alignedTotalSize - sizeof(_heap_header_t);
151 list_entry_init(&newBlock->freeEntry);
152 list_entry_init(&newBlock->listEntry);
153
155 while (last != NULL && (uintptr_t)last > (uintptr_t)newBlock)
156 {
157 last = CONTAINER_OF_SAFE(last->listEntry.prev, _heap_header_t, listEntry);
158 }
159
160 if (last == NULL)
161 {
162 list_push_back(&_heapList, &newBlock->listEntry);
163 }
164 else
165 {
166 list_append(&_heapList, &last->listEntry, &newBlock->listEntry);
167 }
168
169 return newBlock;
170}
171
173{
174 if (block == NULL || newSize == 0)
175 {
176 return;
177 }
178
179 if (!initialized)
180 {
181 return;
182 }
183
184 assert(newSize % _HEAP_ALIGNMENT == 0);
185 uint64_t originalTotalSize = sizeof(_heap_header_t) + block->size;
186 uint64_t newTotalSize = sizeof(_heap_header_t) + newSize;
187
188 _heap_header_t* remainder = (_heap_header_t*)((uintptr_t)block + newTotalSize);
190 remainder->flags = block->flags & _HEAP_ZEROED;
191 remainder->size = originalTotalSize - newTotalSize - sizeof(_heap_header_t);
192 list_entry_init(&remainder->freeEntry);
193 list_entry_init(&remainder->listEntry);
194
195 block->size = newSize;
196
197 list_append(&_heapList, &block->listEntry, &remainder->listEntry);
198
200}
201
203{
204 if (block == NULL)
205 {
206 return;
207 }
208
209 if (!initialized)
210 {
211 return;
212 }
213
214 uint64_t binIndex = _heap_get_bin_index(block->size);
215 if (binIndex == ERR)
216 {
217 return;
218 }
219 list_push_back(&freeLists[binIndex], &block->freeEntry);
220 bitmap_set(&freeBitmap, binIndex);
221}
222
224{
225 if (block == NULL)
226 {
227 return;
228 }
229
230 if (!initialized)
231 {
232 return;
233 }
234
235 uint64_t binIndex = _heap_get_bin_index(block->size);
236 if (binIndex == ERR)
237 {
238 return;
239 }
240 list_remove(&freeLists[binIndex], &block->freeEntry);
241 if (list_is_empty(&freeLists[binIndex]))
242 {
243 bitmap_clear(&freeBitmap, binIndex);
244 }
245}
246
248{
249 if (size == 0)
250 {
251 return NULL;
252 }
253
254 if (!initialized)
255 {
256 return NULL;
257 }
258
260 {
261 uint64_t totalSize = sizeof(_heap_header_t) + size;
263 uint64_t alignedTotalSize = pageAmount * PAGE_SIZE;
264
265 _heap_header_t* block = _heap_map_memory(alignedTotalSize);
266 if (block == NULL)
267 {
268 return NULL;
269 }
270 block->magic = _HEAP_HEADER_MAGIC;
272 block->size = alignedTotalSize - sizeof(_heap_header_t);
273 list_entry_init(&block->freeEntry);
274 list_entry_init(&block->listEntry);
275
276 return block;
277 }
278
279 size = ROUND_UP(size, _HEAP_ALIGNMENT);
280
281 uint64_t index = _heap_get_bin_index(size);
282 _heap_header_t* suitableBlock = NULL;
283
285 if (freeBinIndex != freeBitmap.length)
286 {
287 suitableBlock = CONTAINER_OF(list_pop_first(&freeLists[freeBinIndex]), _heap_header_t, freeEntry);
288 if (list_is_empty(&freeLists[freeBinIndex]))
289 {
290 bitmap_clear(&freeBitmap, freeBinIndex);
291 }
292 }
293
294 if (suitableBlock == NULL)
295 {
296 suitableBlock = _heap_block_new(size);
297 if (suitableBlock == NULL)
298 {
299 return NULL;
300 }
301 }
302
303 suitableBlock->flags |= _HEAP_ALLOCATED;
304 if (suitableBlock->size >= size + sizeof(_heap_header_t) + _HEAP_ALIGNMENT)
305 {
306 _heap_block_split(suitableBlock, size);
307 }
308
309 return suitableBlock;
310}
311
313{
314 if (block == NULL)
315 {
316 return;
317 }
318
319 if (!initialized)
320 {
321 return;
322 }
323
324 if (block->flags & _HEAP_MAPPED)
325 {
327 _heap_unmap_memory(block, sizeof(_heap_header_t) + block->size);
328 return;
329 }
330 else
331 {
333 }
334
335 block->flags &= ~_HEAP_ALLOCATED;
336
339
340 if (next != NULL && !(next->flags & _HEAP_ALLOCATED) && (block->data + block->size == (uint8_t*)next))
341 {
342 uint64_t newSize = block->size + sizeof(_heap_header_t) + next->size;
343 if (newSize <= _HEAP_LARGE_ALLOC_THRESHOLD)
344 {
346 block->size = newSize;
347 block->flags = (block->flags & _HEAP_ZEROED) & (next->flags & _HEAP_ZEROED);
348
349 list_remove(&_heapList, &next->listEntry);
350 }
351 }
352
353 if (prev != NULL && !(prev->flags & _HEAP_ALLOCATED) && (prev->data + prev->size == (uint8_t*)block))
354 {
355 uint64_t newSize = prev->size + sizeof(_heap_header_t) + block->size;
356 if (newSize <= _HEAP_LARGE_ALLOC_THRESHOLD)
357 {
359 prev->size = newSize;
360 prev->flags = (prev->flags & _HEAP_ZEROED) & (block->flags & _HEAP_ZEROED);
361
363
364 block = prev;
365 }
366 }
367
369}
#define assert(expression)
Definition assert.h:29
@ PML_PRESENT
@ PML_WRITE
@ PML_GLOBAL
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:163
void * vmm_unmap(space_t *space, void *virtAddr, uint64_t length)
Unmaps virtual memory from a given address space.
Definition vmm.c:334
@ VMM_ALLOC_OVERWRITE
If any page is already mapped, overwrite the mapping.
Definition vmm.h:123
static void lock_init(lock_t *lock)
Initializes a lock.
Definition lock.h:86
static void lock_release(lock_t *lock)
Releases a lock.
Definition lock.h:146
static void lock_acquire(lock_t *lock)
Acquires a lock, blocking until it is available.
Definition lock.h:103
#define _HEAP_LARGE_ALLOC_THRESHOLD
Definition heap.h:44
void _heap_acquire(void)
Acquire the heap lock.
Definition heap.c:84
void _heap_add_to_free_list(_heap_header_t *block)
Adds a block to the appropriate free list.
Definition heap.c:202
_heap_header_t * _heap_block_new(uint64_t minSize)
Directly maps a new heap block of at least minSize bytes.
Definition heap.c:127
void _heap_unmap_memory(void *addr, uint64_t size)
Unmaps previously mapped memory.
Definition heap.c:50
#define _HEAP_NUM_BINS
Definition heap.h:49
void _heap_init(void)
Initialize the heap.
Definition heap.c:64
void _heap_free(_heap_header_t *block)
Frees a previously allocated heap block.
Definition heap.c:312
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:172
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:247
list_t _heapList
A list of all blocks sorted by address.
Definition heap.c:62
void _heap_remove_from_free_list(_heap_header_t *block)
Removes a block from its free list.
Definition heap.c:223
#define _HEAP_HEADER_MAGIC
Definition heap.h:39
void _heap_release(void)
Release the heap lock.
Definition heap.c:98
#define _HEAP_ALIGNMENT
Definition heap.h:34
uint64_t _heap_get_bin_index(uint64_t size)
Get the bin index for a given size.
Definition heap.c:112
@ _HEAP_ALLOCATED
Block is allocated.
Definition heap.h:56
@ _HEAP_MAPPED
Block is not on the heap, but mapped directly, used for large allocations.
Definition heap.h:57
@ _HEAP_ZEROED
Block is zeroed.
Definition heap.h:58
uint64_t bitmap_find_first_set(bitmap_t *map, uint64_t startIdx, uint64_t endIdx)
Find the first set bit in the bitmap.
void bitmap_init(bitmap_t *map, void *buffer, uint64_t length)
Initialize a bitmap.
Definition bitmap_init.c:3
void bitmap_clear(bitmap_t *map, uint64_t index)
Clear a bit in the bitmap.
Definition bitmap_clear.c:3
void bitmap_set(bitmap_t *map, uint64_t index)
Set a bit in the bitmap.
Definition bitmap_set.c:3
#define BITMAP_BITS_TO_QWORDS(bits)
Convert number of bits to number of qwords.
Definition bitmap.h:34
fd_t open(const char *path)
System call for opening files.
Definition open.c:9
static list_entry_t * list_pop_first(list_t *list)
Pops the first entry from the list.
Definition list.h:375
static list_entry_t * list_last(list_t *list)
Gets the last entry in the list without removing it.
Definition list.h:435
static void list_push_back(list_t *list, list_entry_t *entry)
Pushes an entry to the end of the list.
Definition list.h:343
#define LIST_CREATE(name)
Creates a list initializer.
Definition list.h:174
static void list_remove(list_t *list, list_entry_t *entry)
Removes a list entry from its current list.
Definition list.h:315
static void list_append(list_t *list, list_entry_t *prev, list_entry_t *entry)
Appends an entry to the list.
Definition list.h:290
static bool list_is_empty(list_t *list)
Checks if a list is empty.
Definition list.h:227
static void list_entry_init(list_entry_t *entry)
Initializes a list entry.
Definition list.h:182
static void list_init(list_t *list)
Initializes a list.
Definition list.h:196
#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
The size of a memory page in bytes.
Definition proc.h:106
#define BYTES_TO_PAGES(amount)
Convert a size in bytes to pages.
Definition proc.h:114
void * munmap(void *address, uint64_t length)
System call to unmap mapped memory.
Definition munmap.c:6
@ PROT_READ
Readable memory.
Definition proc.h:131
@ PROT_WRITE
Writable memory.
Definition proc.h:132
#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 bool initialized
Definition heap.c:60
static fd_t zeroDev
Definition heap.c:37
double remainder(double x, double y)
static uint64_t pageAmount
Definition pmm.c:44
static atomic_long next
Definition main.c:11
__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:9
_PUBLIC void * memset(void *s, int c, size_t n)
Definition memset.c:4
uint8_t data[]
Definition heap.h:76
list_entry_t freeEntry
Definition heap.h:74
uint64_t size
Definition heap.h:73
list_entry_t listEntry
Definition heap.h:75
_heap_flags_t flags
Definition heap.h:72
uint32_t magic
Definition heap.h:71
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:38
struct list_entry * prev
The previous entry in the list.
Definition list.h:37
A doubly linked list.
Definition list.h:49
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
@ mtx_plain
Definition threads.h:66
_PUBLIC int mtx_unlock(mtx_t *mtx)
Definition mtx_unlock.c:10