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 #include <zephyr/irq_offload.h>
11 
12 #if CONFIG_MP_MAX_NUM_CPUS < 2
13 #error "SMP test requires at least two CPUs!"
14 #endif
15 
16 #define NUM_THREADS CONFIG_MP_MAX_NUM_CPUS
17 #define STACK_SIZE 1024
18 
19 K_THREAD_STACK_ARRAY_DEFINE(thread_stack, NUM_THREADS, STACK_SIZE);
20 struct k_thread thread[NUM_THREADS];
21 
22 struct isr_args {
23 	volatile bool *sync;
24 	volatile bool *wait;
25 	struct k_thread *target;
26 };
27 
28 volatile bool sync[NUM_THREADS];
29 
30 struct isr_args isr_args[NUM_THREADS];
31 
isr(const void * args)32 static void isr(const void *args)
33 {
34 	const struct isr_args *var = args;
35 
36 	*(var->sync) = true;            /* Flag that ISR is in progress */
37 
38 	while (*(var->wait) == false) { /* Wait upon dependent CPU */
39 	}
40 
41 	k_thread_abort(var->target);    /* Abort thread on another CPU */
42 }
43 
thread_entry(void * p1,void * p2,void * p3)44 static void thread_entry(void *p1, void *p2, void *p3)
45 {
46 	unsigned int index = (unsigned int)(uintptr_t)p1;
47 	struct isr_args *var = p2;
48 
49 	printk("Thread %u started\n", index);
50 
51 	irq_offload(isr, var);
52 
53 	zassert_true(false, "Thread %u did not abort!", index);
54 }
55 
ZTEST(smp_abort,test_smp_thread_abort_deadlock)56 ZTEST(smp_abort, test_smp_thread_abort_deadlock)
57 {
58 	unsigned int  i;
59 	int  priority;
60 
61 	priority = k_thread_priority_get(k_current_get());
62 
63 	/*
64 	 * Each thread will run on its own CPU and invoke an ISR.
65 	 * Each ISR will wait until the next thread enters its ISR
66 	 * before attempting to abort that thread. This ensures that
67 	 * we have a scenario where each CPU is attempting to abort
68 	 * the active thread that was interrupted by an ISR.
69 	 */
70 
71 	for (i = 0; i < NUM_THREADS; i++) {
72 		isr_args[i].sync = &sync[i];
73 		isr_args[i].wait = &sync[(i + 1) % NUM_THREADS];
74 		isr_args[i].target = &thread[(i + 1) % NUM_THREADS];
75 	}
76 
77 	for (i = 0; i < NUM_THREADS; i++) {
78 
79 		k_thread_create(&thread[i], thread_stack[i],
80 				STACK_SIZE, thread_entry,
81 				(void *)(uintptr_t)i, &isr_args[i], NULL,
82 				priority - 1, 0, K_NO_WAIT);
83 	}
84 
85 	for (i = 0; i < NUM_THREADS; i++) {
86 		k_thread_join(&thread[i], K_FOREVER);
87 	}
88 
89 	printk("Done!\n");
90 }
91 
92 ZTEST_SUITE(smp_abort, NULL, NULL, NULL, NULL, NULL);
93