Skip to content

Commit 36f64da

Browse files
committed
tests: lib: Add newlib thread safety test
This commit adds a new test to verify the thread safety of the C standard functions provided by newlib. Only the memory management functions (malloc and free) are tested at this time; this test will be further extended in the future, to verify the thread safety and re-entrancy of all supported newlib functions. Signed-off-by: Stephanos Ioannidis <[email protected]>
1 parent 46a3672 commit 36f64da

File tree

4 files changed

+124
-0
lines changed

4 files changed

+124
-0
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
cmake_minimum_required(VERSION 3.13.1)
4+
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
5+
project(newlib_thread_safety)
6+
7+
FILE(GLOB app_sources src/*.c)
8+
target_sources(app PRIVATE ${app_sources})
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
CONFIG_ZTEST=y
2+
CONFIG_NEWLIB_LIBC=y
3+
CONFIG_TIMESLICE_SIZE=1
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/*
2+
* Copyright (c) 2021 Stephanos Ioannidis <[email protected]>
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
/*
8+
* @file Newlib thread safety 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.h>
16+
#include <ztest.h>
17+
18+
#include <stdio.h>
19+
#include <stdlib.h>
20+
21+
#define THREAD_COUNT (64)
22+
#define STACK_SIZE (512 + CONFIG_TEST_EXTRA_STACKSIZE)
23+
#define TEST_INTERVAL (30) /* seconds */
24+
25+
static struct k_thread tdata[THREAD_COUNT];
26+
static K_THREAD_STACK_ARRAY_DEFINE(tstack, THREAD_COUNT, STACK_SIZE);
27+
28+
void malloc_thread(void *p1, void *p2, void *p3)
29+
{
30+
static atomic_t count;
31+
bool *aborted = p1;
32+
int *volatile ptr;
33+
int val;
34+
35+
while (*aborted == false) {
36+
/* Compute unique value specific to this iteration. */
37+
val = atomic_inc(&count);
38+
39+
/* Allocate memory block and write a unique value to it. */
40+
ptr = malloc(sizeof(int));
41+
zassert_not_null(ptr, "Out of memory");
42+
*ptr = val;
43+
44+
/* Busy wait to increase the likelihood of preemption. */
45+
k_busy_wait(10);
46+
47+
/*
48+
* Verify that the unique value previously written to the
49+
* memory block is valid. This value will become corrupted if
50+
* the newlib heap is not properly synchronised.
51+
*/
52+
zassert_equal(*ptr, val, "Corrupted memory block");
53+
54+
/* Free memory block. */
55+
free(ptr);
56+
}
57+
}
58+
59+
/**
60+
* @brief Test thread safety of newlib memory management functions
61+
*
62+
* This test calls the malloc() and free() functions from multiple threads to
63+
* verify that no corruption occurs in the newlib memory heap.
64+
*/
65+
void test_malloc_thread_safety(void)
66+
{
67+
int i;
68+
k_tid_t tid[THREAD_COUNT];
69+
bool aborted = false;
70+
71+
/* Create worker threads. */
72+
for (i = 0; i < ARRAY_SIZE(tid); i++) {
73+
tid[i] = k_thread_create(&tdata[i], tstack[i], STACK_SIZE,
74+
malloc_thread, &aborted, NULL, NULL,
75+
K_PRIO_PREEMPT(0), 0, K_NO_WAIT);
76+
}
77+
78+
TC_PRINT("Created %d worker threads.\n", THREAD_COUNT);
79+
80+
/* Wait and see if any failures occur. */
81+
TC_PRINT("Waiting %d seconds to see if any failures occur ...\n",
82+
TEST_INTERVAL);
83+
84+
k_sleep(K_SECONDS(TEST_INTERVAL));
85+
86+
/* Abort all worker threads. */
87+
aborted = true;
88+
89+
for (i = 0; i < ARRAY_SIZE(tid); i++) {
90+
k_thread_join(tid[i], K_FOREVER);
91+
}
92+
}
93+
94+
void test_main(void)
95+
{
96+
ztest_test_suite(newlib_thread_safety,
97+
ztest_unit_test(test_malloc_thread_safety));
98+
99+
ztest_run_test_suite(newlib_thread_safety);
100+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
common:
2+
filter: TOOLCHAIN_HAS_NEWLIB == 1
3+
min_ram: 64
4+
tags: clib newlib
5+
6+
tests:
7+
libraries.libc.newlib.thread_safety:
8+
slow: true
9+
libraries.libc.newlib_nano.thread_safety:
10+
slow: true
11+
filter: CONFIG_HAS_NEWLIB_LIBC_NANO
12+
extra_configs:
13+
- CONFIG_NEWLIB_LIBC_NANO=y

0 commit comments

Comments
 (0)