1 /*
2 * Copyright (c) 2021 Nordic Semiconductor ASA.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/sys/heap_listener.h>
8 #include <zephyr/kernel.h>
9 #include <zephyr/ztest.h>
10
11 #include <malloc.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <stddef.h>
15
16 /*
17 * Function used by malloc() to obtain or free memory to the system.
18 * Returns the heap end before applying the change.
19 */
20 extern void *sbrk(intptr_t count);
21
current_heap_end(void)22 static uintptr_t current_heap_end(void)
23 {
24 return (uintptr_t)sbrk(0);
25 }
26
27 static ptrdiff_t heap_difference;
28
heap_resized(uintptr_t heap_id,void * old_heap_end,void * new_heap_end)29 static void heap_resized(uintptr_t heap_id, void *old_heap_end, void *new_heap_end)
30 {
31 ARG_UNUSED(heap_id);
32
33 heap_difference += ((char *)new_heap_end - (char *)old_heap_end);
34 }
35
36 static HEAP_LISTENER_RESIZE_DEFINE(listener, HEAP_ID_LIBC, heap_resized);
37
38 void *ptr;
39
40 /**
41 * @brief Test that heap listener is notified when libc heap size changes.
42 *
43 * This test calls the malloc() and free() followed by malloc_trim() functions
44 * and verifies that the heap listener is notified of allocating or returning
45 * memory from the system.
46 */
ZTEST(newlib_libc_heap_listener,test_alloc_and_trim)47 ZTEST(newlib_libc_heap_listener, test_alloc_and_trim)
48 {
49 uintptr_t saved_heap_end;
50
51 TC_PRINT("Allocating memory...\n");
52
53 heap_listener_register(&listener);
54 saved_heap_end = current_heap_end();
55 ptr = malloc(4096);
56
57 TC_PRINT("Total heap size change: %zi\n", heap_difference);
58
59 zassert_true(heap_difference > 0, "Heap increase not detected");
60 zassert_equal(current_heap_end() - saved_heap_end, heap_difference,
61 "Heap increase not detected");
62
63 TC_PRINT("Freeing memory...\n");
64
65 heap_difference = 0;
66 saved_heap_end = current_heap_end();
67 free(ptr);
68 malloc_trim(0);
69
70 /*
71 * malloc_trim() may not free any memory to the system if there is not enough to free.
72 * Therefore, do not require that heap_difference < 0.
73 */
74 zassert_equal(current_heap_end() - saved_heap_end, heap_difference,
75 "Heap decrease not detected");
76
77 heap_listener_unregister(&listener);
78 }
79
80 ZTEST_SUITE(newlib_libc_heap_listener, NULL, NULL, NULL, NULL, NULL);
81