blob: 9311371f72123f5d80bea40f616b46710ae288a4 [file] [log] [blame]
/*
* Copyright (c) 2011-2016 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr.h>
#include <ztest.h>
#include <debug/object_tracing.h>
extern void test_obj_tracing(void);
#define STSIZE (1024 + CONFIG_TEST_EXTRA_STACKSIZE)
#define N_PHILOSOPHERS 5
#define TOTAL_TEST_NUMBER 2
#define ZTEST_THREADS_CREATED 1
#define TOTAL_THREADS (N_PHILOSOPHERS + 3 + IPM_THREAD + ZTEST_THREADS_CREATED)
#define TOTAL_OBJECTS (N_PHILOSOPHERS)
#define OBJ_LIST_NAME k_sem
#define OBJ_LIST_TYPE struct k_sem
#define FORK(x) (&forks[x])
#define TAKE(x) k_sem_take(x, K_FOREVER)
#define GIVE(x) k_sem_give(x)
#define RANDDELAY(x) k_sleep(10 * (x) + 1)
/* 1 IPM console thread if enabled */
#if defined(CONFIG_IPM_CONSOLE_RECEIVER) && defined(CONFIG_PRINTK)
#define IPM_THREAD 1
#else
#define IPM_THREAD 0
#endif /* CONFIG_IPM_CONSOLE_RECEIVER && CONFIG_PRINTK*/
/* Must account for:
* N Philosopher threads
* 1 Object monitor thread
* 1 System idle thread
* 1 System workqueue thread
* 1 IPM console thread
*/
void *force_sys_work_q_in = (void *)&k_sys_work_q;
K_THREAD_STACK_ARRAY_DEFINE(phil_stack, N_PHILOSOPHERS, STSIZE);
static struct k_thread phil_data[N_PHILOSOPHERS];
K_THREAD_STACK_DEFINE(mon_stack, STSIZE);
static struct k_thread mon_data;
struct k_sem forks[N_PHILOSOPHERS];
K_SEM_DEFINE(f3, -5, 1);
/**
* @brief Object Tracing Tests
* @defgroup kernel_objtracing_tests Object Tracing Tests
* @ingroup all_tests
* @{
* @}
*/
static inline int test_thread_monitor(void)
{
int obj_counter = 0;
struct k_thread *thread_list = NULL;
/* wait a bit to allow any initialization-only threads to terminate */
thread_list = (struct k_thread *)SYS_THREAD_MONITOR_HEAD;
while (thread_list != NULL) {
if (thread_list->base.prio == -1) {
TC_PRINT("PREMPT: %p OPTIONS: 0x%02x, STATE: 0x%02x\n",
thread_list,
thread_list->base.user_options,
thread_list->base.thread_state);
} else {
TC_PRINT("COOP: %p OPTIONS: 0x%02x, STATE: 0x%02x\n",
thread_list,
thread_list->base.user_options,
thread_list->base.thread_state);
}
thread_list =
(struct k_thread *)SYS_THREAD_MONITOR_NEXT(thread_list);
obj_counter++;
}
TC_PRINT("THREAD QUANTITY: %d\n", obj_counter);
return obj_counter;
}
static void object_monitor(void)
{
int obj_counter = 0;
int thread_counter = 0, sem = 0;
void *obj_list = NULL;
k_sem_take(&f3, 0);
/* ztest use one semaphore so use one count less than expected to pass
* test
*/
obj_list = SYS_TRACING_HEAD(OBJ_LIST_TYPE, OBJ_LIST_NAME);
while (obj_list != NULL) {
TC_PRINT("SEMAPHORE REF: %p\n", obj_list);
obj_list = SYS_TRACING_NEXT(OBJ_LIST_TYPE, OBJ_LIST_NAME,
obj_list);
for (sem = 0; sem < N_PHILOSOPHERS; sem++) {
if (obj_list == &forks[sem] || obj_list == &f3) {
obj_counter++;
break;
}
}
}
TC_PRINT("SEMAPHORE QUANTITY: %d\n", obj_counter);
thread_counter += test_thread_monitor();
zassert_true(((thread_counter == TOTAL_THREADS) &&
(obj_counter == TOTAL_OBJECTS)), "test failed");
}
static void phil_entry(void)
{
int counter;
struct k_sem *f1; /* fork #1 */
struct k_sem *f2; /* fork #2 */
static int myId; /* next philosopher ID */
unsigned int pri = irq_lock(); /* interrupt lock level */
int id = myId++; /* current philosopher ID */
irq_unlock(pri);
/* always take the lowest fork first */
if ((id + 1) != N_PHILOSOPHERS) {
f1 = FORK(id);
f2 = FORK(id + 1);
} else {
f1 = FORK(0);
f2 = FORK(id);
}
for (counter = 0; counter < 5; counter++) {
TAKE(f1);
TAKE(f2);
RANDDELAY(id);
GIVE(f2);
GIVE(f1);
RANDDELAY(id);
}
GIVE(&f3);
}
/**
* @brief Trace the number of objects created
*
* @ingroup kernel_objtracing_tests
*
* @details The test uses dining philsophers problem as
* an application that implements multiple threads that
* are synchronized with semaphores.
*/
void test_philosophers_tracing(void)
{
int i;
for (i = 0; i < N_PHILOSOPHERS; i++) {
k_sem_init(&forks[i], 1, 1);
}
/* create philosopher threads */
for (i = 0; i < N_PHILOSOPHERS; i++) {
k_thread_create(&phil_data[i], &phil_stack[i][0], STSIZE,
(k_thread_entry_t)phil_entry, NULL, NULL, NULL,
K_PRIO_COOP(6), 0, K_NO_WAIT);
}
/* create object counter monitor thread */
k_thread_create(&mon_data, mon_stack, STSIZE,
(k_thread_entry_t)object_monitor, NULL, NULL, NULL,
K_PRIO_COOP(7), 0, K_NO_WAIT);
}
void test_main(void)
{
ztest_test_suite(obj_tracing,
ztest_unit_test(test_philosophers_tracing),
ztest_unit_test(test_obj_tracing));
ztest_run_test_suite(obj_tracing);
}