1 /*
2 * Copyright (c) 2024 Intel Corporation.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/tc_util.h>
8 #include <zephyr/ztest.h>
9 #include <zephyr/kernel.h>
10
11 #if CONFIG_MP_MAX_NUM_CPUS < 2
12 #error "SMP test requires at least two CPUs!"
13 #endif
14
15 #define STACK_SIZE 1024
16
17 #define NUM_THREADS 6
18
19 K_THREAD_STACK_ARRAY_DEFINE(thread_stack, NUM_THREADS, STACK_SIZE);
20 struct k_thread thread[NUM_THREADS];
21
22 volatile uint64_t thread_counter[NUM_THREADS];
23
thread_entry(void * p1,void * p2,void * p3)24 static void thread_entry(void *p1, void *p2, void *p3)
25 {
26 struct k_thread *resume_thread = p1;
27 unsigned int self_index = (unsigned int)(uintptr_t)p2;
28
29 while (1) {
30 if (resume_thread != NULL) {
31 k_thread_resume(resume_thread);
32 }
33
34 thread_counter[self_index]++;
35
36 /*
37 * Contentious spinlocks embedded within tight loops (such as
38 * this one) have a CPU bias induced by arch_spin_relax(). We
39 * counteract this by introducing a configurable delay so that
40 * other threads have a chance to acquire the spinlock and
41 * prevent starvation.
42 */
43
44 for (volatile unsigned int i = 0;
45 i < CONFIG_SMP_TEST_RELAX;
46 i++) {
47 }
48
49 if (self_index != 0) {
50 k_thread_suspend(k_current_get());
51 }
52 }
53 }
54
ZTEST(smp_suspend_resume,test_smp_thread_suspend_resume_stress)55 ZTEST(smp_suspend_resume, test_smp_thread_suspend_resume_stress)
56 {
57 unsigned int i;
58 uint64_t counter[NUM_THREADS] = {};
59
60 /* Create the threads */
61
62 printk("Starting ...\n");
63
64 for (i = 0; i < NUM_THREADS; i++) {
65
66 k_thread_create(&thread[i], thread_stack[i],
67 STACK_SIZE, thread_entry,
68 i < (NUM_THREADS - 1) ? &thread[i + 1] : NULL,
69 (void *)(uintptr_t)i, NULL,
70 10 - i, 0, K_FOREVER);
71
72 k_thread_suspend(&thread[i]);
73
74 k_thread_start(&thread[i]);
75 }
76
77 /*
78 * All newly created test threads are currently in the suspend state.
79 * Start the first thread.
80 */
81
82 k_thread_resume(&thread[0]);
83
84 for (unsigned int iteration = 0; iteration < 15; iteration++) {
85 k_sleep(K_MSEC(1000));
86
87 for (i = 0; i < NUM_THREADS; i++) {
88 zassert_false(counter[i] == thread_counter[i],
89 " -- Thread %u is starving: %llu\n",
90 i, thread_counter[i]);
91
92 counter[i] = thread_counter[i];
93
94 }
95 }
96 }
97
98 ZTEST_SUITE(smp_suspend_resume, NULL, NULL, NULL, NULL, NULL);
99