blob: 013fcd9d5a01ec5032f8664d4bee3ce5e4b46c29 [file] [log] [blame]
/*
* Copyright (c) 2024 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/tc_util.h>
#include <zephyr/ztest.h>
#include <zephyr/kernel.h>
#if CONFIG_MP_MAX_NUM_CPUS < 2
#error "SMP test requires at least two CPUs!"
#endif
#define STACK_SIZE 1024
#define NUM_THREADS 6
K_THREAD_STACK_ARRAY_DEFINE(thread_stack, NUM_THREADS, STACK_SIZE);
struct k_thread thread[NUM_THREADS];
volatile uint64_t thread_counter[NUM_THREADS];
static void thread_entry(void *p1, void *p2, void *p3)
{
struct k_thread *resume_thread = p1;
unsigned int self_index = (unsigned int)(uintptr_t)p2;
while (1) {
if (resume_thread != NULL) {
k_thread_resume(resume_thread);
}
thread_counter[self_index]++;
/*
* Contentious spinlocks embedded within tight loops (such as
* this one) have a CPU bias induced by arch_spin_relax(). We
* counteract this by introducing a configurable delay so that
* other threads have a chance to acquire the spinlock and
* prevent starvation.
*/
for (volatile unsigned int i = 0;
i < CONFIG_SMP_TEST_RELAX;
i++) {
}
if (self_index != 0) {
k_thread_suspend(k_current_get());
}
}
}
ZTEST(smp_suspend_resume, test_smp_thread_suspend_resume_stress)
{
unsigned int i;
uint64_t counter[NUM_THREADS] = {};
/* Create the threads */
printk("Starting ...\n");
for (i = 0; i < NUM_THREADS; i++) {
k_thread_create(&thread[i], thread_stack[i],
STACK_SIZE, thread_entry,
i < (NUM_THREADS - 1) ? &thread[i + 1] : NULL,
(void *)(uintptr_t)i, NULL,
10 - i, 0, K_FOREVER);
k_thread_suspend(&thread[i]);
k_thread_start(&thread[i]);
}
/*
* All newly created test threads are currently in the suspend state.
* Start the first thread.
*/
k_thread_resume(&thread[0]);
for (unsigned int iteration = 0; iteration < 15; iteration++) {
k_sleep(K_MSEC(1000));
for (i = 0; i < NUM_THREADS; i++) {
zassert_false(counter[i] == thread_counter[i],
" -- Thread %u is starving: %llu\n",
i, thread_counter[i]);
counter[i] = thread_counter[i];
}
}
}
ZTEST_SUITE(smp_suspend_resume, NULL, NULL, NULL, NULL, NULL);