blob: 04a92891586c7a4806a7a580d9050ef6340bb9b7 [file] [log] [blame]
/*
* Copyright (c) 2018 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <ztest.h>
#include <irq_offload.h>
#include <debug/stack.h>
#include "tests_thread_apis.h"
#define SLEEP_MS 100
#define TEST_STRING "TEST"
#define TEST_STRING_UNLOCKED "TEST_UNLOCKED"
static int tcount;
static bool thread_flag;
static bool create_thread;
static k_tid_t in_callback_tid;
struct k_thread tdata1;
K_THREAD_STACK_DEFINE(tstack1, STACK_SIZE);
static void thread_entry(void *p1, void *p2, void *p3)
{
k_msleep(SLEEP_MS);
}
static void thread_callback(const struct k_thread *thread, void *user_data)
{
char *str = (char *)user_data;
if (thread == &tdata) {
TC_PRINT("%s: Newly added thread found\n", str);
TC_PRINT("%s: tid: %p, prio: %d\n",
str, thread, thread->base.prio);
thread_flag = true;
}
tcount++;
}
static
void thread_callback_unlocked(const struct k_thread *thread, void *user_data)
{
char *str = (char *)user_data;
if (create_thread) {
in_callback_tid = k_thread_create(&tdata1, tstack1,
STACK_SIZE,
(k_thread_entry_t)thread_entry,
NULL, NULL, NULL, K_PRIO_PREEMPT(0),
0, K_NO_WAIT);
create_thread = false;
}
if (thread == &tdata) {
TC_PRINT("%s: Newly added thread found\n", str);
TC_PRINT("%s: tid: %p, prio: %d\n",
str, thread, thread->base.prio);
thread_flag = true;
}
if (thread == &tdata1) {
TC_PRINT("%s: Newly added thread in callback found\n", str);
TC_PRINT("%s: tid: %p, prio: %d\n",
str, thread, thread->base.prio);
thread_flag = true;
k_thread_abort(in_callback_tid);
}
tcount++;
}
/**
* @ingroup kernel_thread_tests
* @brief Test k_thread_foreach API
*
* @details Call k_thread_foreach() at the beginning of the test and
* call it again after creating a thread, See k_thread_foreach()
* iterates over the newly created thread and calls the user passed
* callback function.
*
* @see k_thread_foreach()
*/
void test_k_thread_foreach(void)
{
int count;
k_thread_foreach(thread_callback, TEST_STRING);
/* Check thread_count non-zero, thread_flag
* and stack_flag are not set.
*/
zassert_true(tcount && !thread_flag,
"thread_callback() not getting called");
/* Save the initial thread count */
count = tcount;
/* Create new thread which should add a new entry to the thread list */
k_tid_t tid = k_thread_create(&tdata, tstack,
STACK_SIZE, (k_thread_entry_t)thread_entry, NULL,
NULL, NULL, K_PRIO_PREEMPT(0), 0, K_NO_WAIT);
k_msleep(1);
/* Call k_thread_foreach() and check
* thread_callback is getting called for
* the newly added thread.
*/
tcount = 0;
k_thread_foreach(thread_callback, TEST_STRING);
/* Check thread_count > temp, thread_flag and stack_flag are set */
zassert_true((tcount > count) && thread_flag,
"thread_callback() not getting called");
k_thread_abort(tid);
}
/**
* @brief Test k_thread_foreach_unlock API
*
* @details Call k_thread_foreach_unlocked() at the beginning of the test and
* call it again after creating a thread, See k_thread_foreach_unlocked()
* iterates over the newly created thread and calls the user passed
* callback function.
* In contrast to k_thread_foreach(), k_thread_foreach_unlocked() allow
* callback function created or abort threads
*
* @see k_thread_foreach_unlocked()
* @ingroup kernel_thread_tests
*/
void test_k_thread_foreach_unlocked(void)
{
int count;
thread_flag = false;
tcount = 0;
k_thread_foreach_unlocked(thread_callback_unlocked,
TEST_STRING_UNLOCKED);
/* Check thread_count non-zero, thread_flag
* and stack_flag are not set.
*/
zassert_true(tcount && !thread_flag,
"thread_callback() not getting called");
/* Save the initial thread count */
count = tcount;
/* Create new thread which should add a new entry to the thread list */
k_tid_t tid = k_thread_create(&tdata, tstack,
STACK_SIZE, (k_thread_entry_t)thread_entry, NULL,
NULL, NULL, K_PRIO_PREEMPT(0), 0, K_NO_WAIT);
k_msleep(1);
/* Call k_thread_foreach() and check
* thread_callback is getting called for
* the newly added thread.
* meanwhile, a new thread is created in callback but
* it is not be counted in this iteration
*/
tcount = 0;
create_thread = true;
k_thread_foreach_unlocked(thread_callback_unlocked,
TEST_STRING_UNLOCKED);
/* Check thread_count > temp, thread_flag and stack_flag are set */
zassert_true((tcount > count) && thread_flag,
"thread_callback() not getting called");
/* thread_count increase again,
* as there is a thread is created in last iteration
*/
tcount = 0;
k_thread_foreach_unlocked(thread_callback_unlocked,
TEST_STRING_UNLOCKED);
zassert_true((tcount > count) && thread_flag,
"thread_callback() not getting called");
k_thread_abort(tid);
}
/**
* @brief Test k_thread_foreach API with null callback
*
* @details Call k_thread_foreach() with null callback will trigger __ASSERT()
* and this test thread will be aborted by z_fatal_error()
* @see k_thread_foreach()
* @ingroup kernel_thread_tests
*/
void test_k_thread_foreach_null_cb(void)
{
k_thread_foreach(NULL, TEST_STRING);
}
/**
* @brief Test k_thread_foreach_unlocked API with null callback
*
* @details Call k_thread_foreach_unlocked() with null callback will trigger
* __ASSERT() and this test thread will be aborted by z_fatal_error()
*
* @see k_thread_foreach_unlocked()
* @ingroup kernel_thread_tests
*/
void test_k_thread_foreach_unlocked_null_cb(void)
{
k_thread_foreach_unlocked(NULL, TEST_STRING_UNLOCKED);
}
/**
* @brief Test k_thread_state_str API with null callback
*
* @details It's impossible to sched a thread step by step manually to
* experience each state from _THREAD_PRESTART to _THREAD_DEAD. To cover each
* line of function k_thread_state_str(), set thread_state of tdata1 and check
* the string this function returns
*
* @see k_thread_state_str()
* @ingroup kernel_thread_tests
*/
void test_k_thread_state_str(void)
{
k_tid_t tid = &tdata1;
tid->base.thread_state = 0;
zassert_true(strcmp(k_thread_state_str(tid), "") == 0, NULL);
tid->base.thread_state = _THREAD_DUMMY;
zassert_true(strcmp(k_thread_state_str(tid), "dummy") == 0, NULL);
tid->base.thread_state = _THREAD_PENDING;
zassert_true(strcmp(k_thread_state_str(tid), "pending") == 0, NULL);
tid->base.thread_state = _THREAD_PRESTART;
zassert_true(strcmp(k_thread_state_str(tid), "prestart") == 0, NULL);
tid->base.thread_state = _THREAD_DEAD;
zassert_true(strcmp(k_thread_state_str(tid), "dead") == 0, NULL);
tid->base.thread_state = _THREAD_SUSPENDED;
zassert_true(strcmp(k_thread_state_str(tid), "suspended") == 0, NULL);
tid->base.thread_state = _THREAD_ABORTING;
zassert_true(strcmp(k_thread_state_str(tid), "aborting") == 0, NULL);
tid->base.thread_state = _THREAD_QUEUED;
zassert_true(strcmp(k_thread_state_str(tid), "queued") == 0, NULL);
tid->base.thread_state = 0xFF;
zassert_true(strcmp(k_thread_state_str(tid), "unknown") == 0, NULL);
}