1 /*
2 * Copyright (c) 2021 Stephanos Ioannidis <root@stephanos.io>
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /*
8 * @file Newlib thread-safety stress test
9 *
10 * This file contains a set of tests to verify that the C standard functions
11 * provided by newlib are thread safe (i.e. synchronised) and that the thread-
12 * specific contexts are properly handled (i.e. re-entrant).
13 */
14
15 #include <zephyr/kernel.h>
16 #include <zephyr/ztest.h>
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <malloc.h>
21
22 #define THREAD_COUNT (64)
23 #define STACK_SIZE (512 + CONFIG_TEST_EXTRA_STACK_SIZE)
24 #define TEST_INTERVAL (30) /* seconds */
25
26 #ifdef CONFIG_USERSPACE
27 #define THREAD_OPT (K_USER | K_INHERIT_PERMS)
28 #else
29 #define THREAD_OPT (0)
30 #endif /* CONFIG_USERSPACE */
31
32 static struct k_thread tdata[THREAD_COUNT];
33 static K_THREAD_STACK_ARRAY_DEFINE(tstack, THREAD_COUNT, STACK_SIZE);
34
malloc_thread(void * p1,void * p2,void * p3)35 static void malloc_thread(void *p1, void *p2, void *p3)
36 {
37 static ZTEST_BMEM atomic_t count;
38 bool *aborted = p1;
39 int val;
40 int *volatile ptr;
41
42 while (*aborted == false) {
43 /* Compute unique value specific to this iteration. */
44 val = atomic_inc(&count);
45
46 /* Allocate memory block and write a unique value to it. */
47 ptr = malloc(sizeof(int));
48 zassert_not_null(ptr, "Out of memory");
49 *ptr = val;
50
51 /* Busy wait to increase the likelihood of preemption. */
52 k_busy_wait(10);
53
54 /*
55 * Verify that the unique value previously written to the
56 * memory block is valid. This value will become corrupted if
57 * the newlib heap is not properly synchronised.
58 */
59 zassert_equal(*ptr, val, "Corrupted memory block");
60
61 /* Free memory block. */
62 free(ptr);
63 }
64 }
65
66 /**
67 * @brief Test thread safety of newlib memory management functions
68 *
69 * This test calls the malloc() and free() functions from multiple threads to
70 * verify that no corruption occurs in the newlib memory heap.
71 */
ZTEST(newlib_thread_safety_stress,test_malloc_thread_safety)72 ZTEST(newlib_thread_safety_stress, test_malloc_thread_safety)
73 {
74 int i;
75 k_tid_t tid[THREAD_COUNT];
76 static ZTEST_BMEM bool aborted;
77
78 /* Create worker threads. */
79 for (i = 0; i < ARRAY_SIZE(tid); i++) {
80 tid[i] = k_thread_create(&tdata[i], tstack[i], STACK_SIZE,
81 malloc_thread, &aborted, NULL, NULL,
82 K_PRIO_PREEMPT(0), THREAD_OPT,
83 K_NO_WAIT);
84 }
85
86 TC_PRINT("Created %d worker threads.\n", THREAD_COUNT);
87
88 /* Wait and see if any failures occur. */
89 TC_PRINT("Waiting %d seconds to see if any failures occur ...\n",
90 TEST_INTERVAL);
91
92 k_sleep(K_SECONDS(TEST_INTERVAL));
93
94 /* Abort all worker threads. */
95 aborted = true;
96
97 for (i = 0; i < ARRAY_SIZE(tid); i++) {
98 k_thread_join(tid[i], K_FOREVER);
99 }
100 }
101 ZTEST_SUITE(newlib_thread_safety_stress, NULL, NULL, NULL, NULL, NULL);
102