PatchworkOS  19e446b
A non-POSIX operating system.
Loading...
Searching...
No Matches
heap.h
Go to the documentation of this file.
1#pragma once
2
3#include <stdbool.h>
4#include <stdint.h>
5#include <sys/defs.h>
6#include <sys/list.h>
7#include <sys/proc.h>
8
9#ifdef _KERNEL_
10#include <kernel/sync/lock.h>
11#else
12#include <threads.h>
13#endif
14
15/**
16 * @brief Internal Heap Implementation.
17 * @defgroup libstd_common_heap Heap
18 * @ingroup libstd_common
19 *
20 * We use a "segregated free list" allocator with a set of bins where each bin stores free blocks of size \f$n \cdot
21 * 64\f$ bytes where \f$n\f$ is the index of the bin, up to `_HEAP_LARGE_ALLOC_THRESHOLD`. Above this size, blocks are
22 * mapped directly.
23 *
24 * To allow for coalescing of free blocks, all blocks (allocated and free) are additionally stored in a linked list
25 * sorted by address. When a block is freed, we check the previous and next blocks in memory to see if they are free,
26 * and if so we merge them into a single larger block.
27 *
28 * Included is the internal heap allocation, the functions that the kernel and user space should use are the expected
29 * `malloc()`, `free()`, `realloc()`, etc functions.
30 *
31 * @todo Implement a slab allocator.
32 *
33 * @{
34 */
35
36/**
37 * The memory alignment in bytes of all allocations on the heap.
38 *
39 * We use 64 bytes for better cache line alignment on modern CPUs.
40 */
41#define _HEAP_ALIGNMENT 64
42
43/**
44 * Magic number used to validate heap integrity.
45 */
46#define _HEAP_HEADER_MAGIC 0xDEADBEEF
47
48/**
49 * The threshold size for large allocations, above this size allocations will be mapped directly.
50 */
51#define _HEAP_LARGE_ALLOC_THRESHOLD (PAGE_SIZE * 4)
52
53/**
54 * The number of bins for free lists.
55 */
56#define _HEAP_NUM_BINS (_HEAP_LARGE_ALLOC_THRESHOLD / _HEAP_ALIGNMENT)
57
58/**
59 * @brief Flags for heap blocks.
60 */
61typedef enum
62{
63 _HEAP_ALLOCATED = 1 << 0, ///< Block is allocated.
64 _HEAP_MAPPED = 1 << 1, ///< Block is not on the heap, but mapped directly, used for large allocations.
65 _HEAP_ZEROED = 1 << 2, ///< Block is zeroed.
67
68/**
69 * @brief Header for each heap block.
70 * @struct _heap_header
71 *
72 * Contains metadata for each allocated block in the heap.
73 *
74 * Must have a size that is a multiple of `_HEAP_ALIGNMENT` for cache alignment.
75 */
76typedef struct ALIGNED(_HEAP_ALIGNMENT) _heap_header
77{
78 uint32_t magic;
80 uint64_t size;
81 list_entry_t freeEntry;
82 list_entry_t listEntry;
85
86static_assert(sizeof(_heap_header_t) % _HEAP_ALIGNMENT == 0, "_heap_header_t size must be multiple of 64");
87
88/**
89 * @brief A list of all blocks sorted by address.
90 */
91extern list_t _heapList;
92
93#ifdef _KERNEL_
94extern lock_t _heapLock;
95#else
96extern mtx_t _heapLock;
97#endif
98
99/**
100 * @brief Initialize the heap.
101 */
102void _heap_init(void);
103
104/**
105 * @brief Acquire the heap lock.
106 *
107 * Must be paired with a call to `_heap_release()`.
108 */
109static inline void _heap_acquire(void)
110{
111#ifdef _KERNEL_
113#else
115#endif
116}
117
118/**
119 * @brief Release the heap lock.
120 */
121static inline void _heap_release(void)
122{
123#ifdef _KERNEL_
125#else
127#endif
128}
129
130/**
131 * @brief Get the bin index for a given size.
132 *
133 * @param size The size to get the bin index for.
134 * @return The bin index, or `ERR` if the size is should be treated as a large allocation.
135 */
137
138/**
139 * @brief Directly maps a new heap block of at least `minSize` bytes.
140 *
141 * Must be called with the heap acquired.
142 *
143 * @param minSize The minimum size of the block to create, in bytes.
144 * @return On success, pointer to the new heap block header. On failure, `NULL`.
145 */
147
148/**
149 * @brief Splits a heap block into two blocks, the first of `size` bytes and the second with the remaining bytes.
150 *
151 * Must be called with the heap acquired.
152 *
153 * @param block The block to split.
154 * @param size The size of the first block after the split, in bytes.
155 */
156void _heap_block_split(_heap_header_t* block, uint64_t size);
157
158/**
159 * @brief Adds a block to the appropriate free list.
160 *
161 * Must be called with the heap acquired.
162 *
163 * Will not actually free the block, just add it to the free list.
164 *
165 * Used to keep track of which bins have free blocks using a bitmap.
166 *
167 * @param block The block to add.
168 */
170
171/**
172 * @brief Removes a block from its free list.
173 *
174 * Must be called with the heap acquired.
175 *
176 * Will not actually allocate the block, just remove it from the free list.
177 *
178 * Used to keep track of which bins have free blocks using a bitmap.
179 *
180 * @param block The block to remove.
181 */
183
184/**
185 * @brief Allocates a block of memory of given size.
186 *
187 * Must be called with the heap acquired.
188 *
189 * @param size The size of memory to allocate, in bytes.
190 * @return On success, pointer to the allocated heap block header. On failure, `NULL` and `errno` is set.
191 */
193
194/**
195 * @brief Frees a previously allocated heap block.
196 *
197 * Must be called with the heap acquired.
198 *
199 * Will attempt to coalesce adjacent free blocks.
200 *
201 * @param block The block to free.
202 */
203void _heap_free(_heap_header_t* block);
204
205/**
206 * @brief Directly maps memory of the given size.
207 *
208 * In the kernel this function uses the VMM to map new memory, in user space it uses `/dev/const/zero`.
209 *
210 * @param size The size of memory to map, in bytes.
211 * @return On success, pointer to the mapped memory. On failure, `NULL`.
212 */
213void* _heap_map_memory(uint64_t size);
214
215/**
216 * @brief Unmaps previously mapped memory.
217 *
218 * In the kernel this function uses the VMM to unmap memory, in user space it uses the `munmap()` function.
219 *
220 * @param addr The address of the memory to unmap.
221 * @param size The size of memory to unmap, in bytes.
222 */
223void _heap_unmap_memory(void* addr, uint64_t size);
224
225/** @} */
static fd_t data
Definition dwm.c:21
static void lock_release(lock_t *lock)
Releases a lock.
Definition lock.h:175
static void lock_acquire(lock_t *lock)
Acquires a lock, blocking until it is available.
Definition lock.h:96
static void _heap_acquire(void)
Acquire the heap lock.
Definition heap.h:109
_heap_flags_t
Flags for heap blocks.
Definition heap.h:62
_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
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
static void _heap_release(void)
Release the heap lock.
Definition heap.h:121
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_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 ALIGNED(alignment)
GCC aligned attribute.
Definition defs.h:23
static const path_flag_t flags[]
Definition path.c:47
__UINT32_TYPE__ uint32_t
Definition stdint.h:15
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
__UINT8_TYPE__ uint8_t
Definition stdint.h:11
Header for each heap block.
A entry in a doubly linked list.
Definition list.h:37
A doubly linked list.
Definition list.h:46
A simple ticket lock implementation.
Definition lock.h:44
_PUBLIC int mtx_lock(mtx_t *mtx)
Definition mtx_lock.c:11
_PUBLIC int mtx_unlock(mtx_t *mtx)
Definition mtx_unlock.c:10