| /* |
| * Copyright (c) 2021 Nordic Semiconductor ASA |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #ifndef ZEPHYR_INCLUDE_SYS_HEAP_LISTENER_H |
| #define ZEPHYR_INCLUDE_SYS_HEAP_LISTENER_H |
| |
| #include <stdint.h> |
| #include <toolchain.h> |
| #include <sys/slist.h> |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| #if defined(CONFIG_HEAP_LISTENER) || defined(__DOXYGEN__) |
| |
| /** |
| * @defgroup heap_listener_apis Heap Listener APIs |
| * @{ |
| */ |
| |
| enum heap_event_types { |
| /* |
| * Dummy event so an un-initialized but zero-ed listener node |
| * will not trigger any callbacks. |
| */ |
| HEAP_EVT_UNKNOWN = 0, |
| |
| HEAP_RESIZE, |
| HEAP_ALLOC, |
| HEAP_FREE, |
| HEAP_REALLOC, |
| |
| HEAP_MAX_EVENTS |
| }; |
| |
| /** |
| * @typedef heap_listener_resize_cb_t |
| * @brief Callback used when heap is resized |
| * |
| * @note Minimal C library does not emit this event. |
| * |
| * @param heap_id Identifier of heap being resized |
| * @param old_heap_end Pointer to end of heap before resize |
| * @param new_heap_end Pointer to end of heap after resize |
| */ |
| typedef void (*heap_listener_resize_cb_t)(uintptr_t heap_id, |
| void *old_heap_end, |
| void *new_heap_end); |
| |
| /** |
| * @typedef heap_listener_alloc_cb_t |
| * @brief Callback used when there is heap allocation |
| * |
| * @note Heaps managed by libraries outside of code in |
| * Zephyr main code repository may not emit this event. |
| * |
| * @note The number of bytes allocated may not match exactly |
| * to the request to the allocation function. Internal |
| * mechanism of the heap may allocate more than |
| * requested. |
| * |
| * @param heap_id Heap identifier |
| * @param mem Pointer to the allocated memory |
| * @param bytes Size of allocated memory |
| */ |
| typedef void (*heap_listener_alloc_cb_t)(uintptr_t heap_id, |
| void *mem, size_t bytes); |
| |
| /** |
| * @typedef heap_listener_free_cb_t |
| * @brief Callback used when memory is freed from heap |
| * |
| * @note Heaps managed by libraries outside of code in |
| * Zephyr main code repository may not emit this event. |
| * |
| * @note The number of bytes freed may not match exactly to |
| * the request to the allocation function. Internal |
| * mechanism of the heap dictates how memory is |
| * allocated or freed. |
| * |
| * @param heap_id Heap identifier |
| * @param mem Pointer to the freed memory |
| * @param bytes Size of freed memory |
| */ |
| typedef void (*heap_listener_free_cb_t)(uintptr_t heap_id, |
| void *mem, size_t bytes); |
| |
| struct heap_listener { |
| /** Singly linked list node */ |
| sys_snode_t node; |
| |
| /** |
| * Identifier of the heap whose events are listened. |
| * |
| * It can be a heap pointer, if the heap is represented as an object, |
| * or 0 in the case of the global libc heap. |
| */ |
| uintptr_t heap_id; |
| |
| /** |
| * The heap event to be notified. |
| */ |
| enum heap_event_types event; |
| |
| union { |
| heap_listener_alloc_cb_t alloc_cb; |
| heap_listener_free_cb_t free_cb; |
| heap_listener_resize_cb_t resize_cb; |
| }; |
| }; |
| |
| /** |
| * @brief Register heap event listener |
| * |
| * Add the listener to the global list of heap listeners that can be notified by |
| * different heap implementations upon certain events related to the heap usage. |
| * |
| * @param listener Pointer to the heap_listener object |
| */ |
| void heap_listener_register(struct heap_listener *listener); |
| |
| /** |
| * @brief Unregister heap event listener |
| * |
| * Remove the listener from the global list of heap listeners that can be |
| * notified by different heap implementations upon certain events related to the |
| * heap usage. |
| * |
| * @param listener Pointer to the heap_listener object |
| */ |
| void heap_listener_unregister(struct heap_listener *listener); |
| |
| /** |
| * @brief Notify listeners of heap allocation event |
| * |
| * Notify registered heap event listeners with matching heap identifier that an |
| * allocation has been done on heap |
| * |
| * @param heap_id Heap identifier |
| * @param mem Pointer to the allocated memory |
| * @param bytes Size of allocated memory |
| */ |
| void heap_listener_notify_alloc(uintptr_t heap_id, void *mem, size_t bytes); |
| |
| /** |
| * @brief Notify listeners of heap free event |
| * |
| * Notify registered heap event listeners with matching heap identifier that |
| * memory is freed on heap |
| * |
| * @param heap_id Heap identifier |
| * @param mem Pointer to the freed memory |
| * @param bytes Size of freed memory |
| */ |
| void heap_listener_notify_free(uintptr_t heap_id, void *mem, size_t bytes); |
| |
| /** |
| * @brief Notify listeners of heap resize event |
| * |
| * Notify registered heap event listeners with matching heap identifier that the |
| * heap has been resized. |
| * |
| * @param heap_id Heap identifier |
| * @param old_heap_end Address of the heap end before the change |
| * @param new_heap_end Address of the heap end after the change |
| */ |
| void heap_listener_notify_resize(uintptr_t heap_id, void *old_heap_end, void *new_heap_end); |
| |
| /** |
| * @brief Construct heap identifier from heap pointer |
| * |
| * Construct a heap identifier from a pointer to the heap object, such as |
| * sys_heap. |
| * |
| * @param heap_pointer Pointer to the heap object |
| */ |
| #define HEAP_ID_FROM_POINTER(heap_pointer) ((uintptr_t)heap_pointer) |
| |
| /** |
| * @brief Libc heap identifier |
| * |
| * Identifier of the global libc heap. |
| */ |
| #define HEAP_ID_LIBC ((uintptr_t)0) |
| |
| /** |
| * @brief Define heap event listener node for allocation event |
| * |
| * Sample usage: |
| * @code |
| * void on_heap_alloc(uintptr_t heap_id, void *mem, size_t bytes) |
| * { |
| * LOG_INF("Memory allocated at %p, size %ld", heap_id, mem, bytes); |
| * } |
| * |
| * HEAP_LISTENER_ALLOC_DEFINE(my_listener, HEAP_ID_LIBC, on_heap_alloc); |
| * @endcode |
| * |
| * @param name Name of the heap event listener object |
| * @param _heap_id Identifier of the heap to be listened |
| * @param _alloc_cb Function to be called for allocation event |
| */ |
| #define HEAP_LISTENER_ALLOC_DEFINE(name, _heap_id, _alloc_cb) \ |
| struct heap_listener name = { \ |
| .heap_id = _heap_id, \ |
| .event = HEAP_ALLOC, \ |
| { \ |
| .alloc_cb = _alloc_cb \ |
| }, \ |
| } |
| |
| /** |
| * @brief Define heap event listener node for free event |
| * |
| * Sample usage: |
| * @code |
| * void on_heap_free(uintptr_t heap_id, void *mem, size_t bytes) |
| * { |
| * LOG_INF("Memory freed at %p, size %ld", heap_id, mem, bytes); |
| * } |
| * |
| * HEAP_LISTENER_FREE_DEFINE(my_listener, HEAP_ID_LIBC, on_heap_free); |
| * @endcode |
| * |
| * @param name Name of the heap event listener object |
| * @param _heap_id Identifier of the heap to be listened |
| * @param _free_cb Function to be called for free event |
| */ |
| #define HEAP_LISTENER_FREE_DEFINE(name, _heap_id, _free_cb) \ |
| struct heap_listener name = { \ |
| .heap_id = _heap_id, \ |
| .event = HEAP_FREE, \ |
| { \ |
| .free_cb = _free_cb \ |
| }, \ |
| } |
| |
| /** |
| * @brief Define heap event listener node for resize event |
| * |
| * Sample usage: |
| * @code |
| * void on_heap_resized(uintptr_t heap_id, void *old_heap_end, void *new_heap_end) |
| * { |
| * LOG_INF("Libc heap end moved from %p to %p", old_heap_end, new_heap_end); |
| * } |
| * |
| * HEAP_LISTENER_RESIZE_DEFINE(my_listener, HEAP_ID_LIBC, on_heap_resized); |
| * @endcode |
| * |
| * @param name Name of the heap event listener object |
| * @param _heap_id Identifier of the heap to be listened |
| * @param _resize_cb Function to be called when the listened heap is resized |
| */ |
| #define HEAP_LISTENER_RESIZE_DEFINE(name, _heap_id, _resize_cb) \ |
| struct heap_listener name = { \ |
| .heap_id = _heap_id, \ |
| .event = HEAP_RESIZE, \ |
| { \ |
| .resize_cb = _resize_cb \ |
| }, \ |
| } |
| |
| /** @} */ |
| |
| #else /* CONFIG_HEAP_LISTENER */ |
| |
| #define HEAP_ID_FROM_POINTER(heap_pointer) ((uintptr_t)NULL) |
| |
| static inline void heap_listener_notify_alloc(uintptr_t heap_id, void *mem, size_t bytes) |
| { |
| ARG_UNUSED(heap_id); |
| ARG_UNUSED(mem); |
| ARG_UNUSED(bytes); |
| } |
| |
| static inline void heap_listener_notify_free(uintptr_t heap_id, void *mem, size_t bytes) |
| { |
| ARG_UNUSED(heap_id); |
| ARG_UNUSED(mem); |
| ARG_UNUSED(bytes); |
| } |
| |
| static inline void heap_listener_notify_resize(uintptr_t heap_id, void *old_heap_end, |
| void *new_heap_end) |
| { |
| ARG_UNUSED(heap_id); |
| ARG_UNUSED(old_heap_end); |
| ARG_UNUSED(new_heap_end); |
| } |
| |
| #endif /* CONFIG_HEAP_LISTENER */ |
| |
| #ifdef __cplusplus |
| } |
| #endif |
| |
| #endif /* ZEPHYR_INCLUDE_SYS_HEAP_LISTENER_H */ |