tests: kernel: threads: add a testcase for dynamic thread stacks
Test that automatic thread stack allocation works for both user and kernel threads. Signed-off-by: Christopher Friedt <cfriedt@meta.com>
This commit is contained in:
parent
7b1b2576ac
commit
1323b1ac60
4 changed files with 240 additions and 0 deletions
8
tests/kernel/threads/dynamic_thread_stack/CMakeLists.txt
Normal file
8
tests/kernel/threads/dynamic_thread_stack/CMakeLists.txt
Normal file
|
@ -0,0 +1,8 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
cmake_minimum_required(VERSION 3.20.0)
|
||||
find_package(Zephyr HINTS $ENV{ZEPHYR_BASE})
|
||||
project(dynamic_thread_stack)
|
||||
|
||||
FILE(GLOB app_sources src/*.c)
|
||||
target_sources(app PRIVATE ${app_sources})
|
14
tests/kernel/threads/dynamic_thread_stack/prj.conf
Normal file
14
tests/kernel/threads/dynamic_thread_stack/prj.conf
Normal file
|
@ -0,0 +1,14 @@
|
|||
CONFIG_ZTEST=y
|
||||
CONFIG_ZTEST_NEW_API=y
|
||||
CONFIG_INIT_STACKS=y
|
||||
CONFIG_THREAD_STACK_INFO=y
|
||||
CONFIG_MAX_THREAD_BYTES=5
|
||||
CONFIG_DYNAMIC_THREAD=y
|
||||
CONFIG_DYNAMIC_THREAD_POOL_SIZE=2
|
||||
CONFIG_DYNAMIC_THREAD_ALLOC=y
|
||||
CONFIG_HEAP_MEM_POOL_SIZE=16384
|
||||
CONFIG_ZTEST_STACK_SIZE=2048
|
||||
CONFIG_MAIN_STACK_SIZE=2048
|
||||
|
||||
CONFIG_HW_STACK_PROTECTION=n
|
||||
CONFIG_TEST_HW_STACK_PROTECTION=n
|
142
tests/kernel/threads/dynamic_thread_stack/src/main.c
Normal file
142
tests/kernel/threads/dynamic_thread_stack/src/main.c
Normal file
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* Copyright (c) 2022, Meta
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/ztest.h>
|
||||
|
||||
#define TIMEOUT_MS 500
|
||||
|
||||
#ifdef CONFIG_USERSPACE
|
||||
#define STACK_OBJ_SIZE Z_THREAD_STACK_SIZE_ADJUST(CONFIG_DYNAMIC_THREAD_STACK_SIZE)
|
||||
#else
|
||||
#define STACK_OBJ_SIZE Z_KERNEL_STACK_SIZE_ADJUST(CONFIG_DYNAMIC_THREAD_STACK_SIZE)
|
||||
#endif
|
||||
|
||||
#define MAX_HEAP_STACKS (CONFIG_HEAP_MEM_POOL_SIZE / STACK_OBJ_SIZE)
|
||||
|
||||
ZTEST_DMEM bool flag[CONFIG_DYNAMIC_THREAD_POOL_SIZE];
|
||||
|
||||
static void func(void *arg1, void *arg2, void *arg3)
|
||||
{
|
||||
bool *flag = (bool *)arg1;
|
||||
|
||||
ARG_UNUSED(arg2);
|
||||
ARG_UNUSED(arg3);
|
||||
|
||||
printk("Hello, dynamic world!\n");
|
||||
|
||||
*flag = true;
|
||||
}
|
||||
|
||||
/** @brief Exercise the pool-based thread stack allocator */
|
||||
ZTEST(dynamic_thread_stack, test_dynamic_thread_stack_pool)
|
||||
{
|
||||
static k_tid_t tid[CONFIG_DYNAMIC_THREAD_POOL_SIZE];
|
||||
static struct k_thread th[CONFIG_DYNAMIC_THREAD_POOL_SIZE];
|
||||
static k_thread_stack_t *stack[CONFIG_DYNAMIC_THREAD_POOL_SIZE];
|
||||
|
||||
if (!IS_ENABLED(CONFIG_DYNAMIC_THREAD_PREFER_POOL)) {
|
||||
ztest_test_skip();
|
||||
}
|
||||
|
||||
/* allocate all thread stacks from the pool */
|
||||
for (size_t i = 0; i < CONFIG_DYNAMIC_THREAD_POOL_SIZE; ++i) {
|
||||
stack[i] = k_thread_stack_alloc(CONFIG_DYNAMIC_THREAD_STACK_SIZE,
|
||||
IS_ENABLED(CONFIG_USERSPACE) ? K_USER : 0);
|
||||
|
||||
zassert_not_null(stack[i]);
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_DYNAMIC_THREAD_ALLOC)) {
|
||||
/* ensure 1 thread can be allocated from the heap when the pool is depleted */
|
||||
zassert_ok(k_thread_stack_free(
|
||||
k_thread_stack_alloc(CONFIG_DYNAMIC_THREAD_STACK_SIZE,
|
||||
IS_ENABLED(CONFIG_USERSPACE) ? K_USER : 0)));
|
||||
} else {
|
||||
/* ensure that no more thread stacks can be allocated from the pool */
|
||||
zassert_is_null(k_thread_stack_alloc(CONFIG_DYNAMIC_THREAD_STACK_SIZE,
|
||||
IS_ENABLED(CONFIG_USERSPACE) ? K_USER : 0));
|
||||
}
|
||||
|
||||
/* spawn our threads */
|
||||
for (size_t i = 0; i < CONFIG_DYNAMIC_THREAD_POOL_SIZE; ++i) {
|
||||
tid[i] = k_thread_create(&th[i], stack[i],
|
||||
CONFIG_DYNAMIC_THREAD_STACK_SIZE, func,
|
||||
&flag[i], NULL, NULL, 0,
|
||||
K_USER | K_INHERIT_PERMS, K_NO_WAIT);
|
||||
}
|
||||
|
||||
/* join all threads and check that flags have been set */
|
||||
for (size_t i = 0; i < CONFIG_DYNAMIC_THREAD_POOL_SIZE; ++i) {
|
||||
zassert_ok(k_thread_join(tid[i], K_MSEC(TIMEOUT_MS)));
|
||||
zassert_true(flag[i]);
|
||||
}
|
||||
|
||||
/* clean up stacks allocated from the pool */
|
||||
for (size_t i = 0; i < CONFIG_DYNAMIC_THREAD_POOL_SIZE; ++i) {
|
||||
zassert_ok(k_thread_stack_free(stack[i]));
|
||||
}
|
||||
}
|
||||
|
||||
/** @brief Exercise the heap-based thread stack allocator */
|
||||
ZTEST(dynamic_thread_stack, test_dynamic_thread_stack_alloc)
|
||||
{
|
||||
size_t N;
|
||||
static k_tid_t tid[MAX_HEAP_STACKS];
|
||||
static bool flag[MAX_HEAP_STACKS];
|
||||
static struct k_thread th[MAX_HEAP_STACKS];
|
||||
static k_thread_stack_t *stack[MAX_HEAP_STACKS];
|
||||
|
||||
if (!IS_ENABLED(CONFIG_DYNAMIC_THREAD_PREFER_ALLOC)) {
|
||||
ztest_test_skip();
|
||||
}
|
||||
|
||||
if (!IS_ENABLED(CONFIG_DYNAMIC_THREAD_ALLOC)) {
|
||||
ztest_test_skip();
|
||||
}
|
||||
|
||||
/* allocate all thread stacks from the heap */
|
||||
for (N = 0; N < MAX_HEAP_STACKS; ++N) {
|
||||
stack[N] = k_thread_stack_alloc(CONFIG_DYNAMIC_THREAD_STACK_SIZE,
|
||||
IS_ENABLED(CONFIG_USERSPACE) ? K_USER : 0);
|
||||
zassert_not_null(stack[N]);
|
||||
}
|
||||
|
||||
if (CONFIG_DYNAMIC_THREAD_POOL_SIZE == 0) {
|
||||
/* ensure that no more thread stacks can be allocated from the heap */
|
||||
zassert_is_null(k_thread_stack_alloc(CONFIG_DYNAMIC_THREAD_STACK_SIZE,
|
||||
IS_ENABLED(CONFIG_USERSPACE) ? K_USER : 0));
|
||||
}
|
||||
|
||||
/* spwan our threads */
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
tid[i] = k_thread_create(&th[i], stack[i], 0, func, &flag[i], NULL, NULL, 0,
|
||||
K_USER | K_INHERIT_PERMS, K_NO_WAIT);
|
||||
}
|
||||
|
||||
/* join all threads and check that flags have been set */
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
zassert_ok(k_thread_join(tid[i], K_MSEC(TIMEOUT_MS)));
|
||||
zassert_true(flag[i]);
|
||||
}
|
||||
|
||||
/* clean up stacks allocated from the heap */
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
zassert_ok(k_thread_stack_free(stack[i]));
|
||||
}
|
||||
}
|
||||
|
||||
static void *dynamic_thread_stack_setup(void)
|
||||
{
|
||||
#ifdef CONFIG_USERSPACE
|
||||
k_thread_system_pool_assign(k_current_get());
|
||||
/* k_thread_access_grant(k_current_get(), ... ); */
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ZTEST_SUITE(dynamic_thread_stack, NULL, dynamic_thread_stack_setup, NULL, NULL, NULL);
|
76
tests/kernel/threads/dynamic_thread_stack/testcase.yaml
Normal file
76
tests/kernel/threads/dynamic_thread_stack/testcase.yaml
Normal file
|
@ -0,0 +1,76 @@
|
|||
common:
|
||||
tags: kernel security
|
||||
min_ram: 32
|
||||
integration_platforms:
|
||||
- qemu_x86
|
||||
- qemu_x86_nommu
|
||||
- qemu_x86_64
|
||||
- qemu_cortex_a53
|
||||
- qemu_cortex_a53_smp
|
||||
- qemu_cortex_m3
|
||||
- qemu_riscv32
|
||||
- qemu_riscv32e
|
||||
- qemu_riscv64
|
||||
- qemu_riscv64_smp
|
||||
|
||||
# Permutations of (pool | alloc | user)
|
||||
tests:
|
||||
kernel.threads.dynamic_thread.stack.no_pool.no_alloc.no_user:
|
||||
extra_configs:
|
||||
# 000
|
||||
- CONFIG_DYNAMIC_THREAD_POOL_SIZE=0
|
||||
- CONFIG_DYNAMIC_THREAD_ALLOC=n
|
||||
- CONFIG_USERSPACE=n
|
||||
|
||||
# kernel.threads.dynamic_thread.stack.no_pool.no_alloc.user:
|
||||
# tags: userspace
|
||||
# extra_configs:
|
||||
# # 001
|
||||
# - CONFIG_DYNAMIC_THREAD_POOL_SIZE=0
|
||||
# - CONFIG_DYNAMIC_THREAD_ALLOC=n
|
||||
# - CONFIG_USERSPACE=y
|
||||
|
||||
kernel.threads.dynamic_thread.stack.no_pool.alloc.no_user:
|
||||
extra_configs:
|
||||
# 010
|
||||
- CONFIG_DYNAMIC_THREAD_POOL_SIZE=0
|
||||
- CONFIG_DYNAMIC_THREAD_ALLOC=y
|
||||
- CONFIG_USERSPACE=n
|
||||
|
||||
# kernel.threads.dynamic_thread.stack.no_pool.alloc.user:
|
||||
# tags: userspace
|
||||
# extra_configs:
|
||||
# # 011
|
||||
# - CONFIG_DYNAMIC_THREAD_POOL_SIZE=0
|
||||
# - CONFIG_DYNAMIC_THREAD_ALLOC=y
|
||||
# - CONFIG_USERSPACE=y
|
||||
|
||||
kernel.threads.dynamic_thread.stack.pool.no_alloc.no_user:
|
||||
extra_configs:
|
||||
# 100
|
||||
- CONFIG_DYNAMIC_THREAD_POOL_SIZE=2
|
||||
- CONFIG_DYNAMIC_THREAD_ALLOC=n
|
||||
- CONFIG_USERSPACE=n
|
||||
|
||||
# kernel.threads.dynamic_thread.stack.pool.no_alloc.user:
|
||||
# tags: userspace
|
||||
# extra_configs:
|
||||
# # 101
|
||||
# - CONFIG_DYNAMIC_THREAD_POOL_SIZE=2
|
||||
# - CONFIG_DYNAMIC_THREAD_ALLOC=n
|
||||
# - CONFIG_USERSPACE=y
|
||||
|
||||
kernel.threads.dynamic_thread.stack.pool.alloc.no_user:
|
||||
extra_configs:
|
||||
# 110
|
||||
- CONFIG_DYNAMIC_THREAD_POOL_SIZE=2
|
||||
- CONFIG_DYNAMIC_THREAD_ALLOC=y
|
||||
- CONFIG_USERSPACE=n
|
||||
|
||||
# kernel.threads.dynamic_thread.stack.pool.alloc.user:
|
||||
# tags: userspace
|
||||
# extra_configs:
|
||||
# # 111
|
||||
# - CONFIG_DYNAMIC_THREAD_POOL_SIZE=2
|
||||
# - CONFIG_DYNAMIC_THREAD_ALLOC=y
|
||||
# - CONFIG_USERSPACE=y
|
Loading…
Add table
Add a link
Reference in a new issue