PatchworkOS  966e257
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/list.h>
6#include <sys/proc.h>
7
8/**
9 * @brief Internal Heap Implementation.
10 * @defgroup libstd_heap Heap
11 * @ingroup libstd
12 *
13 * We use a "segregated free list" allocator with a set of bins where each bin stores free blocks of size \f$n \cdot
14 * 64\f$ bytes where \f$n\f$ is the index of the bin, up to `_HEAP_LARGE_ALLOC_THRESHOLD`. Above this size, blocks are
15 * mapped directly.
16 *
17 * To allow for coalescing of free blocks, all blocks (allocated and free) are additionally stored in a linked list
18 * sorted by address. When a block is freed, we check the previous and next blocks in memory to see if they are free,
19 * and if so we merge them into a single larger block.
20 *
21 * Included is the internal heap allocation, the functions that the kernel and user space should use are the expected
22 * `malloc()`, `free()`, `realloc()`, etc functions.
23 *
24 * @todo Implement a slab allocator.
25 *
26 * @{
27 */
28
29/**
30 * The memory alignment in bytes of all allocations on the heap.
31 *
32 * We use 64 bytes for better cache line alignment on modern CPUs.
33 */
34#define _HEAP_ALIGNMENT 64
35
36/**
37 * Magic number used to validate heap integrity.
38 */
39#define _HEAP_HEADER_MAGIC 0xDEADBEEF
40
41/**
42 * The threshold size for large allocations, above this size allocations will be mapped directly.
43 */
44#define _HEAP_LARGE_ALLOC_THRESHOLD (PAGE_SIZE * 4)
45
46/**
47 * The number of bins for free lists.
48 */
49#define _HEAP_NUM_BINS (_HEAP_LARGE_ALLOC_THRESHOLD / _HEAP_ALIGNMENT)
50
51/**
52 * @brief Flags for heap blocks.
53 */
54typedef enum
55{
56 _HEAP_ALLOCATED = 1 << 0, ///< Block is allocated.
57 _HEAP_MAPPED = 1 << 1, ///< Block is not on the heap, but mapped directly, used for large allocations.
58 _HEAP_ZEROED = 1 << 2, ///< Block is zeroed.
60
61/**
62 * @brief Header for each heap block.
63 * @struct _heap_header
64 *
65 * Contains metadata for each allocated block in the heap.
66 *
67 * Must have a size that is a multiple of `_HEAP_ALIGNMENT` for cache alignment.
68 */
78
79static_assert(sizeof(_heap_header_t) % _HEAP_ALIGNMENT == 0, "_heap_header_t size must be multiple of 64");
80
81/**
82 * @brief A list of all blocks sorted by address.
83 */
84extern list_t _heapList;
85
86/**
87 * @brief Initialize the heap.
88 */
89void _heap_init(void);
90
91/**
92 * @brief Acquire the heap lock.
93 *
94 * Must be paired with a call to `_heap_release()`.
95 */
96void _heap_acquire(void);
97
98/**
99 * @brief Release the heap lock.
100 */
101void _heap_release(void);
102
103/**
104 * @brief Get the bin index for a given size.
105 *
106 * @param size The size to get the bin index for.
107 * @return The bin index, or `ERR` if the size is should be treated as a large allocation.
108 */
110
111/**
112 * @brief Directly maps a new heap block of at least `minSize` bytes.
113 *
114 * Must be called with the heap acquired.
115 *
116 * @param minSize The minimum size of the block to create, in bytes.
117 * @return On success, pointer to the new heap block header. On failure, `NULL`.
118 */
120
121/**
122 * @brief Splits a heap block into two blocks, the first of `size` bytes and the second with the remaining bytes.
123 *
124 * Must be called with the heap acquired.
125 *
126 * @param block The block to split.
127 * @param size The size of the first block after the split, in bytes.
128 */
129void _heap_block_split(_heap_header_t* block, uint64_t size);
130
131/**
132 * @brief Adds a block to the appropriate free list.
133 *
134 * Must be called with the heap acquired.
135 *
136 * Will not actually free the block, just add it to the free list.
137 *
138 * Used to keep track of which bins have free blocks using a bitmap.
139 *
140 * @param block The block to add.
141 */
143
144/**
145 * @brief Removes a block from its free list.
146 *
147 * Must be called with the heap acquired.
148 *
149 * Will not actually allocate the block, just remove it from the free list.
150 *
151 * Used to keep track of which bins have free blocks using a bitmap.
152 *
153 * @param block The block to remove.
154 */
156
157/**
158 * @brief Allocates a block of memory of given size.
159 *
160 * Must be called with the heap acquired.
161 *
162 * @param size The size of memory to allocate, in bytes.
163 * @return On success, pointer to the allocated heap block header. On failure, `NULL` and `errno` is set.
164 */
166
167/**
168 * @brief Frees a previously allocated heap block.
169 *
170 * Must be called with the heap acquired.
171 *
172 * Will attempt to coalesce adjacent free blocks.
173 *
174 * @param block The block to free.
175 */
176void _heap_free(_heap_header_t* block);
177
178/**
179 * @brief Directly maps memory of the given size.
180 *
181 * In the kernel this function uses the VMM to map new memory, in user space it uses `/dev/zero`.
182 *
183 * @param size The size of memory to map, in bytes.
184 * @return On success, pointer to the mapped memory. On failure, `NULL`.
185 */
186void* _heap_map_memory(uint64_t size);
187
188/**
189 * @brief Unmaps previously mapped memory.
190 *
191 * In the kernel this function uses the VMM to unmap memory, in user space it uses the `munmap()` function.
192 *
193 * @param addr The address of the memory to unmap.
194 * @param size The size of memory to unmap, in bytes.
195 */
196void _heap_unmap_memory(void* addr, uint64_t size);
197
198/** @} */
static fd_t data
Definition dwm.c:21
_heap_flags_t
Flags for heap blocks.
Definition heap.h:55
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
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 size)
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
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
__UINT32_TYPE__ uint32_t
Definition stdint.h:15
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
__UINT8_TYPE__ uint8_t
Definition stdint.h:11
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
Header for each heap block.
A entry in a doubly linked list.
Definition list.h:36
A doubly linked list.
Definition list.h:49