/* * Copyright (c) 2024 Intel Corporation. * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #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);