blob: 294bb2d85b5478f05425b47be1656b25b317e486 [file] [log] [blame]
/*
* Copyright (c) 2018 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <ztest.h>
#include <kernel.h>
#include <cmsis_os2.h>
#define STACKSZ 512
/* This is used to check the thread yield functionality between 2 threads */
static int thread_yield_check;
static int thread_yield_check_dynamic;
static K_THREAD_STACK_DEFINE(test_stack1, STACKSZ);
static osThreadAttr_t thread1_attr = {
.name = "Thread1",
.stack_mem = &test_stack1,
.stack_size = STACKSZ,
.priority = osPriorityHigh,
};
static K_THREAD_STACK_DEFINE(test_stack2, STACKSZ);
static osThreadAttr_t thread2_attr = {
.name = "Thread2",
.stack_mem = &test_stack2,
.stack_size = STACKSZ,
.priority = osPriorityHigh,
};
struct thread1_args {
int *yield_check;
const char *name;
};
static void thread1(void *argument)
{
osStatus_t status;
osThreadId_t thread_id;
const char *name;
struct thread1_args *args = (struct thread1_args *)argument;
thread_id = osThreadGetId();
zassert_true(thread_id != NULL, "Failed getting Thread ID");
name = osThreadGetName(thread_id);
zassert_true(strcmp(args->name, name) == 0,
"Failed getting Thread name");
/* This thread starts off at a high priority (same as thread2) */
(*args->yield_check)++;
zassert_equal(*args->yield_check, 1, NULL);
/* Yield to thread2 which is of same priority */
status = osThreadYield();
zassert_true(status == osOK, "Error doing thread yield");
/* thread_yield_check should now be 2 as it was incremented
* in thread2.
*/
zassert_equal(*args->yield_check, 2, NULL);
osThreadExit();
}
static void thread2(void *argument)
{
u32_t i, num_threads, max_num_threads = 5;
osThreadId_t *thread_array;
int *yield_check = (int *)argument;
/* By now thread1 would have set thread_yield_check to 1 and would
* have yielded the CPU. Incrementing it over here would essentially
* confirm that the yield was indeed executed.
*/
(*yield_check)++;
thread_array = k_calloc(max_num_threads, sizeof(osThreadId_t));
num_threads = osThreadEnumerate(thread_array, max_num_threads);
zassert_equal(num_threads, 2,
"Incorrect number of cmsis rtos v2 threads");
for (i = 0; i < num_threads; i++) {
zassert_true(
osThreadGetStackSize(thread_array[i]) <= STACKSZ,
"stack size allocated is not what is expected");
zassert_true(
osThreadGetStackSpace(thread_array[i]) <= STACKSZ - 4,
"stack size remaining is not what is expected");
}
zassert_equal(osThreadGetState(thread_array[1]), osThreadReady,
"Thread not in ready state");
zassert_equal(osThreadGetState(thread_array[0]), osThreadRunning,
"Thread not in running state");
zassert_equal(osThreadSuspend(thread_array[1]), osOK, "");
zassert_equal(osThreadGetState(thread_array[1]), osThreadBlocked,
"Thread not in blocked state");
zassert_equal(osThreadResume(thread_array[1]), osOK, "");
zassert_equal(osThreadGetState(thread_array[1]), osThreadReady,
"Thread not in ready state");
k_free(thread_array);
/* Yield back to thread1 which is of same priority */
osThreadYield();
}
static void thread_apis_common(int *yield_check,
const char *thread1_name,
osThreadAttr_t *thread1_attr,
osThreadAttr_t *thread2_attr)
{
osThreadId_t id1;
osThreadId_t id2;
struct thread1_args args = {
.yield_check = yield_check,
.name = thread1_name
};
id1 = osThreadNew(thread1, &args, thread1_attr);
zassert_true(id1 != NULL, "Failed creating thread1");
id2 = osThreadNew(thread2, yield_check, thread2_attr);
zassert_true(id2 != NULL, "Failed creating thread2");
zassert_equal(osThreadGetCount(), 2,
"Incorrect number of cmsis rtos v2 threads");
do {
osDelay(100);
} while (*yield_check != 2);
}
void test_thread_apis_dynamic(void)
{
thread_apis_common(&thread_yield_check_dynamic, "ZephyrThread",
NULL, NULL);
}
void test_thread_apis(void)
{
thread_apis_common(&thread_yield_check, thread1_attr.name,
&thread1_attr, &thread2_attr);
}
static osPriority_t OsPriorityInvalid = 60;
/* This is used to indicate the completion of processing for thread3 */
static int thread3_state;
static int thread3_state_dynamic;
static K_THREAD_STACK_DEFINE(test_stack3, STACKSZ);
static osThreadAttr_t thread3_attr = {
.name = "Thread3",
.stack_mem = &test_stack3,
.stack_size = STACKSZ,
.priority = osPriorityNormal,
};
static void thread3(void *argument)
{
osStatus_t status;
osPriority_t rv;
osThreadId_t id = osThreadGetId();
osPriority_t prio = osThreadGetPriority(id);
int *state = (int *)argument;
/* Lower the priority of the current thread */
osThreadSetPriority(id, osPriorityBelowNormal);
rv = osThreadGetPriority(id);
zassert_equal(rv, osPriorityBelowNormal,
"Expected priority to be changed to %d, not %d",
(int)osPriorityBelowNormal, (int)rv);
/* Increase the priority of the current thread */
osThreadSetPriority(id, osPriorityAboveNormal);
rv = osThreadGetPriority(id);
zassert_equal(rv, osPriorityAboveNormal,
"Expected priority to be changed to %d, not %d",
(int)osPriorityAboveNormal, (int)rv);
/* Restore the priority of the current thread */
osThreadSetPriority(id, prio);
rv = osThreadGetPriority(id);
zassert_equal(rv, prio,
"Expected priority to be changed to %d, not %d",
(int)prio, (int)rv);
/* Try to set unsupported priority and assert failure */
status = osThreadSetPriority(id, OsPriorityInvalid);
zassert_true(status == osErrorParameter,
"Something's wrong with osThreadSetPriority!");
/* Indication that thread3 is done with its processing */
*state = 1;
/* Keep looping till it gets killed */
do {
osDelay(100);
} while (1);
}
static void thread_prior_common(int *state, osThreadAttr_t *attr)
{
osStatus_t status;
osThreadId_t id3;
id3 = osThreadNew(thread3, state, attr);
zassert_true(id3 != NULL, "Failed creating thread3");
/* Keep delaying 10 milliseconds to ensure thread3 is done with
* its execution. It loops at the end and is terminated here.
*/
do {
osDelay(10);
} while (*state == 0);
status = osThreadTerminate(id3);
zassert_true(status == osOK, "Error terminating thread3");
/* Try to set priority to inactive thread and assert failure */
status = osThreadSetPriority(id3, osPriorityNormal);
zassert_true(status == osErrorResource,
"Something's wrong with osThreadSetPriority!");
/* Try to terminate inactive thread and assert failure */
status = osThreadTerminate(id3);
zassert_true(status == osErrorResource,
"Something's wrong with osThreadTerminate!");
*state = 0;
}
void test_thread_prio_dynamic(void)
{
thread_prior_common(&thread3_state_dynamic, NULL);
}
void test_thread_prio(void)
{
thread_prior_common(&thread3_state, &thread3_attr);
}
#define DELAY_MS 1000
#define DELTA_MS 500
static void thread5(void *argument)
{
printk(" * Thread B started.\n");
osDelay(_ms_to_ticks(DELAY_MS));
printk(" * Thread B joining...\n");
}
static void thread4(void *argument)
{
osThreadId_t tB = argument;
osStatus_t status;
printk(" + Thread A started.\n");
status = osThreadJoin(tB);
zassert_equal(status, osOK, "osThreadJoin thread B failed!");
printk(" + Thread A joining...\n");
}
void test_thread_join(void)
{
osThreadAttr_t attr = { 0 };
s64_t time_stamp;
s64_t milliseconds_spent;
osThreadId_t tA, tB;
osStatus_t status;
attr.attr_bits = osThreadJoinable;
time_stamp = k_uptime_get();
printk(" - Creating thread B...\n");
tB = osThreadNew(thread5, NULL, &attr);
zassert_not_null(tB, "Failed to create thread B with osThreadNew!");
printk(" - Creating thread A...\n");
tA = osThreadNew(thread4, tB, &attr);
zassert_not_null(tA, "Failed to create thread A with osThreadNew!");
printk(" - Waiting for thread B to join...\n");
status = osThreadJoin(tB);
zassert_equal(status, osOK, "osThreadJoin thread B failed!");
if (status == osOK) {
printk(" - Thread B joined.\n");
}
milliseconds_spent = k_uptime_delta(&time_stamp);
zassert_true((milliseconds_spent >= DELAY_MS - DELTA_MS) &&
(milliseconds_spent <= DELAY_MS + DELTA_MS),
"Join completed but was too fast or too slow.");
printk(" - Waiting for thread A to join...\n");
status = osThreadJoin(tA);
zassert_equal(status, osOK, "osThreadJoin thread A failed!");
if (status == osOK) {
printk(" - Thread A joined.\n");
}
}
void test_thread_detached(void)
{
osThreadId_t thread;
osStatus_t status;
thread = osThreadNew(thread5, NULL, NULL); /* osThreadDetached */
zassert_not_null(thread, "Failed to create thread with osThreadNew!");
osDelay(_ms_to_ticks(DELAY_MS - DELTA_MS));
status = osThreadJoin(thread);
zassert_equal(status, osErrorResource,
"Incorrect status returned from osThreadJoin!");
osDelay(_ms_to_ticks(DELTA_MS));
}
void thread6(void *argument)
{
osThreadId_t thread = argument;
osStatus_t status;
status = osThreadJoin(thread);
zassert_equal(status, osErrorResource,
"Incorrect status returned from osThreadJoin!");
}
void test_thread_joinable_detach(void)
{
osThreadAttr_t attr = { 0 };
osThreadId_t tA, tB;
osStatus_t status;
attr.attr_bits = osThreadJoinable;
tA = osThreadNew(thread5, NULL, &attr);
zassert_not_null(tA, "Failed to create thread with osThreadNew!");
tB = osThreadNew(thread6, tA, &attr);
zassert_not_null(tB, "Failed to create thread with osThreadNew!");
osDelay(_ms_to_ticks(DELAY_MS - DELTA_MS));
status = osThreadDetach(tA);
zassert_equal(status, osOK, "osThreadDetach failed.");
osDelay(_ms_to_ticks(DELTA_MS));
}
void test_thread_joinable_terminate(void)
{
osThreadAttr_t attr = { 0 };
osThreadId_t tA, tB;
osStatus_t status;
attr.attr_bits = osThreadJoinable;
tA = osThreadNew(thread5, NULL, &attr);
zassert_not_null(tA, "Failed to create thread with osThreadNew!");
tB = osThreadNew(thread6, tA, &attr);
zassert_not_null(tB, "Failed to create thread with osThreadNew!");
osDelay(_ms_to_ticks(DELAY_MS - DELTA_MS));
status = osThreadTerminate(tA);
zassert_equal(status, osOK, "osThreadTerminate failed.");
osDelay(_ms_to_ticks(DELTA_MS));
}