PatchworkOS  19e446b
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/fs.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>
13
15
16void* _heap_map_memory(uint64_t size)
17{
19 if (addr == NULL)
20 {
21 return NULL;
22 }
23 memset(addr, 0, size);
24
25 return addr;
26}
27
28void _heap_unmap_memory(void* addr, uint64_t size)
29{
30 vmm_unmap(NULL, addr, size);
31}
32
33#else
34
35#include <stdlib.h>
36#include <threads.h>
37
39
40static fd_t zeroDev = ERR;
41
43{
44 if (zeroDev == ERR)
45 {
46 zeroDev = open("/dev/const/zero:rw");
47 if (zeroDev == ERR)
48 {
49 errno = ENOMEM;
50 return NULL;
51 }
52 }
53
54 void* addr = mmap(zeroDev, NULL, size, PROT_READ | PROT_WRITE);
55 if (addr == NULL)
56 {
57 return NULL;
58 }
59
60 return addr;
61}
62
63void _heap_unmap_memory(void* addr, uint64_t size)
64{
65 munmap(addr, size);
66}
67
68#endif
69
72
74
75void _heap_init(void)
76{
77#ifdef _KERNEL_
79#else
81#endif
82 for (uint64_t i = 0; i < _HEAP_NUM_BINS; i++)
83 {
85 }
86}
87
89{
91 {
92 return ERR;
93 }
94
95 if (size < _HEAP_ALIGNMENT)
96 {
97 return 0;
98 }
99
100 return (size / _HEAP_ALIGNMENT) - 1;
101}
102
104{
105 if (minSize == 0)
106 {
107 return NULL;
108 }
109
110 uint64_t totalSize = MAX(sizeof(_heap_header_t) + minSize, PAGE_SIZE);
111 uint64_t pageAmount = BYTES_TO_PAGES(totalSize);
112 uint64_t alignedTotalSize = pageAmount * PAGE_SIZE;
113
114 _heap_header_t* newBlock = _heap_map_memory(alignedTotalSize);
115 if (newBlock == NULL)
116 {
117 return NULL;
118 }
119 newBlock->magic = _HEAP_HEADER_MAGIC;
120 newBlock->flags = _HEAP_ZEROED;
121 newBlock->size = alignedTotalSize - sizeof(_heap_header_t);
122 list_entry_init(&newBlock->freeEntry);
123 list_entry_init(&newBlock->listEntry);
124
126 while (last != NULL && (uintptr_t)last > (uintptr_t)newBlock)
127 {
128 last = CONTAINER_OF_SAFE(last->listEntry.prev, _heap_header_t, listEntry);
129 }
130
131 if (last == NULL)
132 {
133 list_push_back(&_heapList, &newBlock->listEntry);
134 }
135 else
136 {
137 list_append(&last->listEntry, &newBlock->listEntry);
138 }
139
140 return newBlock;
141}
142
144{
145 if (block == NULL || newSize == 0)
146 {
147 return;
148 }
149
150 assert(newSize % _HEAP_ALIGNMENT == 0);
151 uint64_t originalTotalSize = sizeof(_heap_header_t) + block->size;
152 uint64_t newTotalSize = sizeof(_heap_header_t) + newSize;
153
154 _heap_header_t* remainder = (_heap_header_t*)((uintptr_t)block + newTotalSize);
156 remainder->flags = block->flags & _HEAP_ZEROED;
157 remainder->size = originalTotalSize - newTotalSize - sizeof(_heap_header_t);
158 list_entry_init(&remainder->freeEntry);
159 list_entry_init(&remainder->listEntry);
160
161 block->size = newSize;
162
163 list_append(&block->listEntry, &remainder->listEntry);
164
166}
167
169{
170 if (block == NULL)
171 {
172 return;
173 }
174
175 uint64_t binIndex = _heap_get_bin_index(block->size);
176 if (binIndex == ERR)
177 {
178 return;
179 }
180 list_push_back(&freeLists[binIndex], &block->freeEntry);
181 bitmap_set(&freeBitmap, binIndex);
182}
183
185{
186 if (block == NULL)
187 {
188 return;
189 }
190
191 uint64_t binIndex = _heap_get_bin_index(block->size);
192 if (binIndex == ERR)
193 {
194 return;
195 }
196 list_remove(&block->freeEntry);
197 if (list_is_empty(&freeLists[binIndex]))
198 {
199 bitmap_clear(&freeBitmap, binIndex);
200 }
201}
202
204{
205 if (size == 0)
206 {
207 return NULL;
208 }
209
211 {
212 uint64_t totalSize = sizeof(_heap_header_t) + size;
213 uint64_t pageAmount = BYTES_TO_PAGES(totalSize);
214 uint64_t alignedTotalSize = pageAmount * PAGE_SIZE;
215
216 _heap_header_t* block = _heap_map_memory(alignedTotalSize);
217 if (block == NULL)
218 {
219 return NULL;
220 }
221 block->magic = _HEAP_HEADER_MAGIC;
222 block->flags = _HEAP_ALLOCATED | _HEAP_MAPPED | _HEAP_ZEROED;
223 block->size = alignedTotalSize - sizeof(_heap_header_t);
224 list_entry_init(&block->freeEntry);
225 list_entry_init(&block->listEntry);
226
227 return block;
228 }
229
230 size = ROUND_UP(size, _HEAP_ALIGNMENT);
231
232 uint64_t index = _heap_get_bin_index(size);
233 _heap_header_t* suitableBlock = NULL;
234
235 uint64_t freeBinIndex = bitmap_find_first_set(&freeBitmap, index, _HEAP_NUM_BINS);
236 if (freeBinIndex != freeBitmap.length)
237 {
238 suitableBlock = CONTAINER_OF(list_pop_front(&freeLists[freeBinIndex]), _heap_header_t, freeEntry);
239 if (list_is_empty(&freeLists[freeBinIndex]))
240 {
241 bitmap_clear(&freeBitmap, freeBinIndex);
242 }
243 }
244
245 if (suitableBlock == NULL)
246 {
247 suitableBlock = _heap_block_new(size);
248 if (suitableBlock == NULL)
249 {
250 return NULL;
251 }
252 }
253
254 suitableBlock->flags |= _HEAP_ALLOCATED;
255 if (suitableBlock->size >= size + sizeof(_heap_header_t) + _HEAP_ALIGNMENT)
256 {
257 _heap_block_split(suitableBlock, size);
258 }
259
260 return suitableBlock;
261}
262
264{
265 if (block == NULL)
266 {
267 return;
268 }
269
270 if (block->flags & _HEAP_MAPPED)
271 {
272 assert(block->size > _HEAP_LARGE_ALLOC_THRESHOLD);
273 _heap_unmap_memory(block, sizeof(_heap_header_t) + block->size);
274 return;
275 }
276
277 assert(block->size <= _HEAP_LARGE_ALLOC_THRESHOLD);
278
279 block->flags &= ~_HEAP_ALLOCATED;
280
281 _heap_header_t* prev = CONTAINER_OF_SAFE(block->listEntry.prev, _heap_header_t, listEntry);
282 _heap_header_t* next = CONTAINER_OF_SAFE(block->listEntry.next, _heap_header_t, listEntry);
283
284 if (next != NULL && !(next->flags & _HEAP_ALLOCATED) && (block->data + block->size == (uint8_t*)next))
285 {
286 uint64_t newSize = block->size + sizeof(_heap_header_t) + next->size;
287 if (newSize <= _HEAP_LARGE_ALLOC_THRESHOLD)
288 {
290 block->size = newSize;
291 block->flags = (block->flags & _HEAP_ZEROED) & (next->flags & _HEAP_ZEROED);
292
293 list_remove(&next->listEntry);
294 }
295 }
296
297 if (prev != NULL && !(prev->flags & _HEAP_ALLOCATED) && (prev->data + prev->size == (uint8_t*)block))
298 {
299 uint64_t newSize = prev->size + sizeof(_heap_header_t) + block->size;
300 if (newSize <= _HEAP_LARGE_ALLOC_THRESHOLD)
301 {
303 prev->size = newSize;
304 prev->flags = (prev->flags & _HEAP_ZEROED) & (block->flags & _HEAP_ZEROED);
305
306 list_remove(&block->listEntry);
307
308 block = prev;
309 }
310 }
311
313}
#define assert(expression)
Definition assert.h:29
@ PML_PRESENT
@ PML_WRITE
@ PML_GLOBAL
void * vmm_alloc(space_t *space, void *virtAddr, size_t length, size_t alignment, pml_flags_t pmlFlags, vmm_alloc_flags_t allocFlags)
Allocates and maps virtual memory in a given address space.
Definition vmm.c:153
void * vmm_unmap(space_t *space, void *virtAddr, size_t length)
Unmaps virtual memory from a given address space.
Definition vmm.c:336
@ VMM_ALLOC_OVERWRITE
If any page is already mapped, overwrite the mapping.
Definition vmm.h:122
static void lock_init(lock_t *lock)
Initializes a lock.
Definition lock.h:79
#define _HEAP_LARGE_ALLOC_THRESHOLD
Definition heap.h:51
_heap_header_t
Definition heap.h:84
void _heap_add_to_free_list(_heap_header_t *block)
Adds a block to the appropriate free list.
Definition heap.c:168
_heap_header_t * _heap_block_new(uint64_t minSize)
Directly maps a new heap block of at least minSize bytes.
Definition heap.c:103
void _heap_unmap_memory(void *addr, uint64_t size)
Unmaps previously mapped memory.
Definition heap.c:63
#define _HEAP_NUM_BINS
Definition heap.h:56
void _heap_init(void)
Initialize the heap.
Definition heap.c:75
mtx_t _heapLock
Definition heap.c:38
void _heap_free(_heap_header_t *block)
Frees a previously allocated heap block.
Definition heap.c:263
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:143
void * _heap_map_memory(uint64_t size)
Directly maps memory of the given size.
Definition heap.c:42
_heap_header_t * _heap_alloc(uint64_t size)
Allocates a block of memory of given size.
Definition heap.c:203
list_t _heapList
A list of all blocks sorted by address.
Definition heap.c:73
void _heap_remove_from_free_list(_heap_header_t *block)
Removes a block from its free list.
Definition heap.c:184
#define _HEAP_HEADER_MAGIC
Definition heap.h:46
#define _HEAP_ALIGNMENT
Definition heap.h:41
uint64_t _heap_get_bin_index(uint64_t size)
Get the bin index for a given size.
Definition heap.c:88
@ _HEAP_ALLOCATED
Block is allocated.
Definition heap.h:63
@ _HEAP_MAPPED
Block is not on the heap, but mapped directly, used for large allocations.
Definition heap.h:64
@ _HEAP_ZEROED
Block is zeroed.
Definition heap.h:65
#define ENOMEM
Out of memory.
Definition errno.h:92
#define errno
Error number variable.
Definition errno.h:27
#define BITMAP_CREATE_ZERO(name, bits)
Define and create a zero-initialized bitmap and its buffer.
Definition bitmap.h:83
static uint64_t bitmap_find_first_set(bitmap_t *map, uint64_t startIdx, uint64_t endIdx)
Find the first set bit in the bitmap.
Definition bitmap.h:350
static void bitmap_clear(bitmap_t *map, uint64_t index)
Clear a bit in the bitmap.
Definition bitmap.h:244
static void bitmap_set(bitmap_t *map, uint64_t index)
Set a bit in the bitmap.
Definition bitmap.h:190
fd_t open(const char *path)
System call for opening files.
Definition open.c:8
static void list_remove(list_entry_t *entry)
Removes a list entry from its current list.
Definition list.h:290
static list_entry_t * list_last(list_t *list)
Gets the last entry in the list without removing it.
Definition list.h:423
static void list_push_back(list_t *list, list_entry_t *entry)
Pushes an entry to the end of the list.
Definition list.h:322
#define LIST_CREATE(name)
Creates a list initializer.
Definition list.h:163
static void list_append(list_entry_t *prev, list_entry_t *entry)
Appends an entry to the list.
Definition list.h:268
static bool list_is_empty(list_t *list)
Checks if a list is empty.
Definition list.h:210
static void list_entry_init(list_entry_t *entry)
Initializes a list entry.
Definition list.h:173
static list_entry_t * list_pop_front(list_t *list)
Pops the first entry from the list.
Definition list.h:366
static void list_init(list_t *list)
Initializes a list.
Definition list.h:185
#define ROUND_UP(number, multiple)
Definition math.h:21
#define MAX(x, y)
Definition math.h:17
void * mmap(fd_t fd, void *address, size_t length, prot_t prot)
System call to map memory from a file.
Definition mmap.c:6
#define BYTES_TO_PAGES(amount)
Convert a size in bytes to pages.
Definition proc.h:107
void * munmap(void *address, size_t length)
System call to unmap mapped memory.
Definition munmap.c:6
@ PROT_READ
Readable memory.
Definition proc.h:124
@ PROT_WRITE
Writable memory.
Definition proc.h:125
#define NULL
Pointer error value.
Definition NULL.h:25
#define ERR
Integer error value.
Definition ERR.h:17
#define PAGE_SIZE
The size of a memory page in bytes.
Definition PAGE_SIZE.h:8
#define CONTAINER_OF(ptr, type, member)
Container of macro.
__UINT64_TYPE__ fd_t
File descriptor type.
Definition fd_t.h:10
#define CONTAINER_OF_SAFE(ptr, type, member)
Safe container of macro.
static list_t freeLists[_HEAP_NUM_BINS]
Definition heap.c:70
static fd_t zeroDev
Definition heap.c:40
double remainder(double x, double y)
static atomic_long next
Definition main.c:12
__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 void * memset(void *s, int c, size_t n)
Definition memset.c:4
A doubly linked list.
Definition list.h:46
A simple ticket lock implementation.
Definition lock.h:44
_PUBLIC int mtx_init(mtx_t *mtx, int type)
Definition mtx_init.c:10
@ mtx_plain
Definition threads.h:66