Line data Source code
1 0 : /*
2 : * Copyright (c) 2021 Nordic Semiconductor ASA
3 : *
4 : * SPDX-License-Identifier: Apache-2.0
5 : */
6 :
7 : #ifndef ZEPHYR_INCLUDE_SYS_HEAP_LISTENER_H
8 : #define ZEPHYR_INCLUDE_SYS_HEAP_LISTENER_H
9 :
10 : #include <stdint.h>
11 : #include <zephyr/toolchain.h>
12 : #include <zephyr/sys/slist.h>
13 :
14 : #ifdef __cplusplus
15 : extern "C" {
16 : #endif
17 :
18 : #if defined(CONFIG_HEAP_LISTENER) || defined(__DOXYGEN__)
19 :
20 : /**
21 : * @defgroup heap_listener_apis Heap Listener APIs
22 : * @ingroup heaps
23 : * @{
24 : */
25 :
26 0 : enum heap_event_types {
27 : /*
28 : * Dummy event so an un-initialized but zero-ed listener node
29 : * will not trigger any callbacks.
30 : */
31 : HEAP_EVT_UNKNOWN = 0,
32 :
33 : HEAP_RESIZE,
34 : HEAP_ALLOC,
35 : HEAP_FREE,
36 : HEAP_REALLOC,
37 :
38 : HEAP_MAX_EVENTS
39 : };
40 :
41 : /**
42 : * @typedef heap_listener_resize_cb_t
43 : * @brief Callback used when heap is resized
44 : *
45 : * @note Minimal C library does not emit this event.
46 : *
47 : * @param heap_id Identifier of heap being resized
48 : * @param old_heap_end Pointer to end of heap before resize
49 : * @param new_heap_end Pointer to end of heap after resize
50 : */
51 1 : typedef void (*heap_listener_resize_cb_t)(uintptr_t heap_id,
52 : void *old_heap_end,
53 : void *new_heap_end);
54 :
55 : /**
56 : * @typedef heap_listener_alloc_cb_t
57 : * @brief Callback used when there is heap allocation
58 : *
59 : * @note Heaps managed by libraries outside of code in
60 : * Zephyr main code repository may not emit this event.
61 : *
62 : * @note The number of bytes allocated may not match exactly
63 : * to the request to the allocation function. Internal
64 : * mechanism of the heap may allocate more than
65 : * requested.
66 : *
67 : * @param heap_id Heap identifier
68 : * @param mem Pointer to the allocated memory
69 : * @param bytes Size of allocated memory
70 : */
71 1 : typedef void (*heap_listener_alloc_cb_t)(uintptr_t heap_id,
72 : void *mem, size_t bytes);
73 :
74 : /**
75 : * @typedef heap_listener_free_cb_t
76 : * @brief Callback used when memory is freed from heap
77 : *
78 : * @note Heaps managed by libraries outside of code in
79 : * Zephyr main code repository may not emit this event.
80 : *
81 : * @note The number of bytes freed may not match exactly to
82 : * the request to the allocation function. Internal
83 : * mechanism of the heap dictates how memory is
84 : * allocated or freed.
85 : *
86 : * @param heap_id Heap identifier
87 : * @param mem Pointer to the freed memory
88 : * @param bytes Size of freed memory
89 : */
90 1 : typedef void (*heap_listener_free_cb_t)(uintptr_t heap_id,
91 : void *mem, size_t bytes);
92 :
93 0 : struct heap_listener {
94 : /** Singly linked list node */
95 1 : sys_snode_t node;
96 :
97 : /**
98 : * Identifier of the heap whose events are listened.
99 : *
100 : * It can be a heap pointer, if the heap is represented as an object,
101 : * or 0 in the case of the global libc heap.
102 : */
103 1 : uintptr_t heap_id;
104 :
105 : /**
106 : * The heap event to be notified.
107 : */
108 1 : enum heap_event_types event;
109 :
110 : union {
111 0 : heap_listener_alloc_cb_t alloc_cb;
112 0 : heap_listener_free_cb_t free_cb;
113 0 : heap_listener_resize_cb_t resize_cb;
114 0 : };
115 : };
116 :
117 : /**
118 : * @brief Register heap event listener
119 : *
120 : * Add the listener to the global list of heap listeners that can be notified by
121 : * different heap implementations upon certain events related to the heap usage.
122 : *
123 : * @param listener Pointer to the heap_listener object
124 : */
125 1 : void heap_listener_register(struct heap_listener *listener);
126 :
127 : /**
128 : * @brief Unregister heap event listener
129 : *
130 : * Remove the listener from the global list of heap listeners that can be
131 : * notified by different heap implementations upon certain events related to the
132 : * heap usage.
133 : *
134 : * @param listener Pointer to the heap_listener object
135 : */
136 1 : void heap_listener_unregister(struct heap_listener *listener);
137 :
138 : /**
139 : * @brief Notify listeners of heap allocation event
140 : *
141 : * Notify registered heap event listeners with matching heap identifier that an
142 : * allocation has been done on heap
143 : *
144 : * @param heap_id Heap identifier
145 : * @param mem Pointer to the allocated memory
146 : * @param bytes Size of allocated memory
147 : */
148 1 : void heap_listener_notify_alloc(uintptr_t heap_id, void *mem, size_t bytes);
149 :
150 : /**
151 : * @brief Notify listeners of heap free event
152 : *
153 : * Notify registered heap event listeners with matching heap identifier that
154 : * memory is freed on heap
155 : *
156 : * @param heap_id Heap identifier
157 : * @param mem Pointer to the freed memory
158 : * @param bytes Size of freed memory
159 : */
160 1 : void heap_listener_notify_free(uintptr_t heap_id, void *mem, size_t bytes);
161 :
162 : /**
163 : * @brief Notify listeners of heap resize event
164 : *
165 : * Notify registered heap event listeners with matching heap identifier that the
166 : * heap has been resized.
167 : *
168 : * @param heap_id Heap identifier
169 : * @param old_heap_end Address of the heap end before the change
170 : * @param new_heap_end Address of the heap end after the change
171 : */
172 1 : void heap_listener_notify_resize(uintptr_t heap_id, void *old_heap_end, void *new_heap_end);
173 :
174 : /**
175 : * @brief Construct heap identifier from heap pointer
176 : *
177 : * Construct a heap identifier from a pointer to the heap object, such as
178 : * sys_heap.
179 : *
180 : * @param heap_pointer Pointer to the heap object
181 : */
182 1 : #define HEAP_ID_FROM_POINTER(heap_pointer) ((uintptr_t)heap_pointer)
183 :
184 : /**
185 : * @brief Libc heap identifier
186 : *
187 : * Identifier of the global libc heap.
188 : */
189 1 : #define HEAP_ID_LIBC ((uintptr_t)0)
190 :
191 : /**
192 : * @brief Define heap event listener node for allocation event
193 : *
194 : * Sample usage:
195 : * @code
196 : * void on_heap_alloc(uintptr_t heap_id, void *mem, size_t bytes)
197 : * {
198 : * LOG_INF("Memory allocated at %p, size %ld", mem, bytes);
199 : * }
200 : *
201 : * HEAP_LISTENER_ALLOC_DEFINE(my_listener, HEAP_ID_LIBC, on_heap_alloc);
202 : * @endcode
203 : *
204 : * @param name Name of the heap event listener object
205 : * @param _heap_id Identifier of the heap to be listened
206 : * @param _alloc_cb Function to be called for allocation event
207 : */
208 1 : #define HEAP_LISTENER_ALLOC_DEFINE(name, _heap_id, _alloc_cb) \
209 : struct heap_listener name = { \
210 : .heap_id = _heap_id, \
211 : .event = HEAP_ALLOC, \
212 : { \
213 : .alloc_cb = _alloc_cb \
214 : }, \
215 : }
216 :
217 : /**
218 : * @brief Define heap event listener node for free event
219 : *
220 : * Sample usage:
221 : * @code
222 : * void on_heap_free(uintptr_t heap_id, void *mem, size_t bytes)
223 : * {
224 : * LOG_INF("Memory freed at %p, size %ld", mem, bytes);
225 : * }
226 : *
227 : * HEAP_LISTENER_FREE_DEFINE(my_listener, HEAP_ID_LIBC, on_heap_free);
228 : * @endcode
229 : *
230 : * @param name Name of the heap event listener object
231 : * @param _heap_id Identifier of the heap to be listened
232 : * @param _free_cb Function to be called for free event
233 : */
234 1 : #define HEAP_LISTENER_FREE_DEFINE(name, _heap_id, _free_cb) \
235 : struct heap_listener name = { \
236 : .heap_id = _heap_id, \
237 : .event = HEAP_FREE, \
238 : { \
239 : .free_cb = _free_cb \
240 : }, \
241 : }
242 :
243 : /**
244 : * @brief Define heap event listener node for resize event
245 : *
246 : * Sample usage:
247 : * @code
248 : * void on_heap_resized(uintptr_t heap_id, void *old_heap_end, void *new_heap_end)
249 : * {
250 : * LOG_INF("Libc heap end moved from %p to %p", old_heap_end, new_heap_end);
251 : * }
252 : *
253 : * HEAP_LISTENER_RESIZE_DEFINE(my_listener, HEAP_ID_LIBC, on_heap_resized);
254 : * @endcode
255 : *
256 : * @param name Name of the heap event listener object
257 : * @param _heap_id Identifier of the heap to be listened
258 : * @param _resize_cb Function to be called when the listened heap is resized
259 : */
260 1 : #define HEAP_LISTENER_RESIZE_DEFINE(name, _heap_id, _resize_cb) \
261 : struct heap_listener name = { \
262 : .heap_id = _heap_id, \
263 : .event = HEAP_RESIZE, \
264 : { \
265 : .resize_cb = _resize_cb \
266 : }, \
267 : }
268 :
269 : /** @} */
270 :
271 : #else /* CONFIG_HEAP_LISTENER */
272 :
273 : #define HEAP_ID_FROM_POINTER(heap_pointer) ((uintptr_t)NULL)
274 :
275 : static inline void heap_listener_notify_alloc(uintptr_t heap_id, void *mem, size_t bytes)
276 : {
277 : ARG_UNUSED(heap_id);
278 : ARG_UNUSED(mem);
279 : ARG_UNUSED(bytes);
280 : }
281 :
282 : static inline void heap_listener_notify_free(uintptr_t heap_id, void *mem, size_t bytes)
283 : {
284 : ARG_UNUSED(heap_id);
285 : ARG_UNUSED(mem);
286 : ARG_UNUSED(bytes);
287 : }
288 :
289 : static inline void heap_listener_notify_resize(uintptr_t heap_id, void *old_heap_end,
290 : void *new_heap_end)
291 : {
292 : ARG_UNUSED(heap_id);
293 : ARG_UNUSED(old_heap_end);
294 : ARG_UNUSED(new_heap_end);
295 : }
296 :
297 : #endif /* CONFIG_HEAP_LISTENER */
298 :
299 : #ifdef __cplusplus
300 : }
301 : #endif
302 :
303 : #endif /* ZEPHYR_INCLUDE_SYS_HEAP_LISTENER_H */
|