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