-
Notifications
You must be signed in to change notification settings - Fork 7k
/
Copy pathsys_heap.h
214 lines (200 loc) · 8.89 KB
/
sys_heap.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
/*
* Copyright (c) 2019 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_SYS_SYS_HEAP_H_
#define ZEPHYR_INCLUDE_SYS_SYS_HEAP_H_
#include <stddef.h>
#include <stdbool.h>
#include <zephyr/types.h>
/* Simple, fast heap implementation.
*
* A more or less conventional segregated fit allocator with
* power-of-two buckets.
*
* Excellent space efficiency. Chunks can be split arbitrarily in 8
* byte units. Overhead is only four bytes per allocated chunk (eight
* bytes for heaps >256kb or on 64 bit systems), plus a log2-sized
* array of 2-word bucket headers. No coarse alignment restrictions
* on blocks, they can be split and merged (in units of 8 bytes)
* arbitrarily.
*
* Simple API. Initialize at runtime with any blob of memory and not
* a macro-generated, carefully aligned static array. Allocate and
* free by user pointer and not an opaque block handle.
*
* Good fragmentation resistance. Freed blocks are always immediately
* merged with adjacent free blocks. Allocations are attempted from a
* sample of the smallest bucket that might fit, falling back rapidly
* to the smallest block guaranteed to fit. Split memory remaining in
* the chunk is always returned immediately to the heap for other
* allocation.
*
* Excellent performance with firmly bounded runtime. All operations
* are constant time (though there is a search of the smallest bucket
* that has a compile-time-configurable upper bound, setting this to
* extreme values results in an effectively linear search of the
* list), objectively fast (~hundred instructions) and and amenable to
* locked operation.
*/
/* Note: the init_mem/bytes fields are for the static initializer to
* have somewhere to put the arguments. The actual heap metadata at
* runtime lives in the heap memory itself and this struct simply
* functions as an opaque pointer. Would be good to clean this up and
* put the two values somewhere else, though it would make
* SYS_HEAP_DEFINE a little hairy to write.
*/
struct sys_heap {
struct z_heap *heap;
void *init_mem;
size_t init_bytes;
};
struct z_heap_stress_result {
uint32_t total_allocs;
uint32_t successful_allocs;
uint32_t total_frees;
uint64_t accumulated_in_use_bytes;
};
/** @brief Initialize sys_heap
*
* Initializes a sys_heap struct to manage the specified memory.
*
* @param heap Heap to initialize
* @param mem Untyped pointer to unused memory
* @param bytes Size of region pointed to by @a mem
*/
void sys_heap_init(struct sys_heap *heap, void *mem, size_t bytes);
/** @brief Allocate memory from a sys_heap
*
* Returns a pointer to a block of unused memory in the heap. This
* memory will not otherwise be used until it is freed with
* sys_heap_free(). If no memory can be allocated, NULL will be
* returned. The allocated memory is guaranteed to have a starting
* address which is a multiple of sizeof(void *). If a bigger alignment
* is necessary then sys_heap_aligned_alloc() should be used instead.
*
* @note The sys_heap implementation is not internally synchronized.
* No two sys_heap functions should operate on the same heap at the
* same time. All locking must be provided by the user.
*
* @param heap Heap from which to allocate
* @param bytes Number of bytes requested
* @return Pointer to memory the caller can now use
*/
void *sys_heap_alloc(struct sys_heap *heap, size_t bytes);
/** @brief Allocate aligned memory from a sys_heap
*
* Behaves in all ways like sys_heap_alloc(), except that the returned
* memory (if available) will have a starting address in memory which
* is a multiple of the specified power-of-two alignment value in
* bytes. With align=0 this behaves exactly like sys_heap_alloc().
* The resulting memory can be returned to the heap using sys_heap_free().
*
* @param heap Heap from which to allocate
* @param align Alignment in bytes, must be a power of two
* @param bytes Number of bytes requested
* @return Pointer to memory the caller can now use
*/
void *sys_heap_aligned_alloc(struct sys_heap *heap, size_t align, size_t bytes);
/** @brief Free memory into a sys_heap
*
* De-allocates a pointer to memory previously returned from
* sys_heap_alloc such that it can be used for other purposes. The
* caller must not use the memory region after entry to this function.
*
* @note The sys_heap implementation is not internally synchronized.
* No two sys_heap functions should operate on the same heap at the
* same time. All locking must be provided by the user.
*
* @param heap Heap to which to return the memory
* @param mem A pointer previously returned from sys_heap_alloc()
*/
void sys_heap_free(struct sys_heap *heap, void *mem);
/** @brief Expand the size of an existing allocation
*
* Returns a pointer to a new memory region with the same contents,
* but a different allocated size. If the new allocation can be
* expanded in place, the pointer returned will be identical.
* Otherwise the data will be copies to a new block and the old one
* will be freed as per sys_heap_free(). If the specified size is
* smaller than the original, the block will be truncated in place and
* the remaining memory returned to the heap. If the allocation of a
* new block fails, then NULL will be returned and the old block will
* not be freed or modified.
*
* @note The return of a NULL on failure is a different behavior than
* POSIX realloc(), which specifies that the original pointer will be
* returned (i.e. it is not possible to safely detect realloc()
* failure in POSIX, but it is here).
*
* @param heap Heap from which to allocate
* @param ptr Original pointer returned from a previous allocation
* @param align Alignment in bytes, must be a power of two
* @param bytes Number of bytes requested for the new block
* @return Pointer to memory the caller can now use, or NULL
*/
void *sys_heap_aligned_realloc(struct sys_heap *heap, void *ptr,
size_t align, size_t bytes);
#define sys_heap_realloc(heap, ptr, bytes) \
sys_heap_aligned_realloc(heap, ptr, 0, bytes)
/** @brief Validate heap integrity
*
* Validates the internal integrity of a sys_heap. Intended for unit
* test and validation code, though potentially useful as a user API
* for applications with complicated runtime reliability requirements.
* Note: this cannot catch every possible error, but if it returns
* true then the heap is in a consistent state and can correctly
* handle any sys_heap_alloc() request and free any live pointer
* returned from a previou allocation.
*
* @param heap Heap to validate
* @return true, if the heap is valid, otherwise false
*/
bool sys_heap_validate(struct sys_heap *heap);
/** @brief sys_heap stress test rig
*
* Test rig for heap allocation validation. This will loop for @a
* op_count cycles, in each iteration making a random choice to
* allocate or free a pointer of randomized (power law) size based on
* heuristics designed to keep the heap in a state where it is near @a
* target_percent full. Allocation and free operations are provided
* by the caller as callbacks (i.e. this can in theory test any heap).
* Results, including counts of frees and successful/unsuccessful
* allocations, are returnewd via the @result struct.
*
* @param alloc_fn Callback to perform an allocation. Passes back the @a
* arg parameter as a context handle.
* @param free_fn Callback to perform a free of a pointer returned from
* @a alloc. Passes back the @a arg parameter as a
* context handle.
* @param arg Context handle to pass back to the callbacks
* @param total_bytes Size of the byte array the heap was initialized in
* @param op_count How many iterations to test
* @param scratch_mem A pointer to scratch memory to be used by the
* test. Should be about 1/2 the size of the heap
* for tests that need to stress fragmentation.
* @param scratch_bytes Size of the memory pointed to by @a scratch_mem
* @param target_percent Percentage fill value (1-100) to which the
* random allocation choices will seek. High
* values will result in significant allocation
* failures and a very fragmented heap.
* @param result Struct into which to store test results.
*/
void sys_heap_stress(void *(*alloc_fn)(void *arg, size_t bytes),
void (*free_fn)(void *arg, void *p),
void *arg, size_t total_bytes,
uint32_t op_count,
void *scratch_mem, size_t scratch_bytes,
int target_percent,
struct z_heap_stress_result *result);
/** @brief Print heap internal structure information to the console
*
* Print information on the heap structure such as its size, chunk buckets,
* chunk list and some statistics for debugging purpose.
*
* @param heap Heap to print information about
* @param dump_chunks True to print the entire heap chunk list
*/
void sys_heap_print_info(struct sys_heap *heap, bool dump_chunks);
#endif /* ZEPHYR_INCLUDE_SYS_SYS_HEAP_H_ */