| /* |
| * Copyright (c) 2021 Stephanos Ioannidis <root@stephanos.io> |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| /* |
| * @file Newlib thread-safety stress test |
| * |
| * This file contains a set of tests to verify that the C standard functions |
| * provided by newlib are thread safe (i.e. synchronised) and that the thread- |
| * specific contexts are properly handled (i.e. re-entrant). |
| */ |
| |
| #include <zephyr/kernel.h> |
| #include <zephyr/ztest.h> |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <malloc.h> |
| |
| #define THREAD_COUNT (64) |
| #define STACK_SIZE (512 + CONFIG_TEST_EXTRA_STACK_SIZE) |
| #define TEST_INTERVAL (30) /* seconds */ |
| |
| #ifdef CONFIG_USERSPACE |
| #define THREAD_OPT (K_USER | K_INHERIT_PERMS) |
| #else |
| #define THREAD_OPT (0) |
| #endif /* CONFIG_USERSPACE */ |
| |
| static struct k_thread tdata[THREAD_COUNT]; |
| static K_THREAD_STACK_ARRAY_DEFINE(tstack, THREAD_COUNT, STACK_SIZE); |
| |
| static void malloc_thread(void *p1, void *p2, void *p3) |
| { |
| static ZTEST_BMEM atomic_t count; |
| bool *aborted = p1; |
| int val; |
| int *volatile ptr; |
| |
| while (*aborted == false) { |
| /* Compute unique value specific to this iteration. */ |
| val = atomic_inc(&count); |
| |
| /* Allocate memory block and write a unique value to it. */ |
| ptr = malloc(sizeof(int)); |
| zassert_not_null(ptr, "Out of memory"); |
| *ptr = val; |
| |
| /* Busy wait to increase the likelihood of preemption. */ |
| k_busy_wait(10); |
| |
| /* |
| * Verify that the unique value previously written to the |
| * memory block is valid. This value will become corrupted if |
| * the newlib heap is not properly synchronised. |
| */ |
| zassert_equal(*ptr, val, "Corrupted memory block"); |
| |
| /* Free memory block. */ |
| free(ptr); |
| } |
| } |
| |
| /** |
| * @brief Test thread safety of newlib memory management functions |
| * |
| * This test calls the malloc() and free() functions from multiple threads to |
| * verify that no corruption occurs in the newlib memory heap. |
| */ |
| ZTEST(newlib_thread_safety_stress, test_malloc_thread_safety) |
| { |
| int i; |
| k_tid_t tid[THREAD_COUNT]; |
| static ZTEST_BMEM bool aborted; |
| |
| /* Create worker threads. */ |
| for (i = 0; i < ARRAY_SIZE(tid); i++) { |
| tid[i] = k_thread_create(&tdata[i], tstack[i], STACK_SIZE, |
| malloc_thread, &aborted, NULL, NULL, |
| K_PRIO_PREEMPT(0), THREAD_OPT, |
| K_NO_WAIT); |
| } |
| |
| TC_PRINT("Created %d worker threads.\n", THREAD_COUNT); |
| |
| /* Wait and see if any failures occur. */ |
| TC_PRINT("Waiting %d seconds to see if any failures occur ...\n", |
| TEST_INTERVAL); |
| |
| k_sleep(K_SECONDS(TEST_INTERVAL)); |
| |
| /* Abort all worker threads. */ |
| aborted = true; |
| |
| for (i = 0; i < ARRAY_SIZE(tid); i++) { |
| k_thread_join(tid[i], K_FOREVER); |
| } |
| } |
| ZTEST_SUITE(newlib_thread_safety_stress, NULL, NULL, NULL, NULL, NULL); |