1 /*
2  * Copyright (c) 2018 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/ztest.h>
8 
9 #include <zephyr/irq_offload.h>
10 
11 #include "tests_thread_apis.h"
12 
13 static int thread2_data;
14 
15 K_SEM_DEFINE(sem_thread2, 0, 1);
16 K_SEM_DEFINE(sem_thread1, 0, 1);
17 
18 struct isr_arg {
19 	k_tid_t thread;
20 	int     prio;
21 };
22 
23 static struct isr_arg prio_args;
24 
25 /**
26  * @brief Test changing a thread's priority from an ISR
27  */
test_isr(const void * arg)28 static void test_isr(const void *arg)
29 {
30 	const struct isr_arg *data = arg;
31 
32 	k_thread_priority_set(data->thread, data->prio);
33 }
34 
35 /**
36  * @brief Test thread behavior when its priority is changed
37  */
thread2_set_prio_test(void * p1,void * p2,void * p3)38 void thread2_set_prio_test(void *p1, void *p2, void *p3)
39 {
40 	ARG_UNUSED(p1);
41 	ARG_UNUSED(p2);
42 	ARG_UNUSED(p3);
43 
44 	/* lower thread2 priority by 5 */
45 	k_sem_take(&sem_thread2, K_FOREVER);
46 	thread2_data = k_thread_priority_get(k_current_get());
47 	k_sem_give(&sem_thread1);
48 
49 	/* raise thread2 priority by 10 */
50 	k_sem_take(&sem_thread2, K_FOREVER);
51 	thread2_data = k_thread_priority_get(k_current_get());
52 	k_sem_give(&sem_thread1);
53 
54 	/* restore thread2 priority */
55 	k_sem_take(&sem_thread2, K_FOREVER);
56 	thread2_data = k_thread_priority_get(k_current_get());
57 	k_sem_give(&sem_thread1);
58 }
59 
60 /**
61  * @ingroup kernel_thread_tests
62  * @brief Test setting and verifying thread priorities
63  *
64  * @details This test creates a thread with a lower priority than the
65  * current thread. It then sets the priority of the thread to a
66  * higher value, and checks that the priority has been set correctly.
67  *
68  * @see k_thread_priority_set(), k_thread_priority_get()
69  */
ZTEST(threads_lifecycle,test_threads_priority_set)70 ZTEST(threads_lifecycle, test_threads_priority_set)
71 {
72 	int rv;
73 	int prio = k_thread_priority_get(k_current_get());
74 
75 	/* Lower the priority of the current thread (thread1) */
76 	k_thread_priority_set(k_current_get(), prio + 2);
77 	rv = k_thread_priority_get(k_current_get());
78 	zassert_equal(rv, prio + 2,
79 			"Expected priority to be changed to %d, not %d\n",
80 			prio + 2, rv);
81 
82 	/* Raise the priority of the current thread (thread1) */
83 	k_thread_priority_set(k_current_get(), prio - 2);
84 	rv = k_thread_priority_get(k_current_get());
85 	zassert_equal(rv, prio - 2,
86 			"Expected priority to be changed to %d, not %d\n",
87 			prio - 2, rv);
88 
89 	/* Restore the priority of the current thread (thread1) */
90 	k_thread_priority_set(k_current_get(), prio);
91 	rv = k_thread_priority_get(k_current_get());
92 	zassert_equal(rv, prio,
93 			"Expected priority to be changed to %d, not %d\n",
94 			prio, rv);
95 
96 	/* create thread with lower priority */
97 	int thread2_prio = prio + 1;
98 
99 	k_tid_t thread2_id = k_thread_create(&tdata, tstack, STACK_SIZE,
100 			thread2_set_prio_test,
101 			NULL, NULL, NULL, thread2_prio, 0,
102 			K_NO_WAIT);
103 
104 	/* Lower the priority of thread2 */
105 	k_thread_priority_set(thread2_id, thread2_prio + 2);
106 	k_sem_give(&sem_thread2);
107 	k_sem_take(&sem_thread1, K_FOREVER);
108 	zassert_equal(thread2_data, thread2_prio + 2,
109 			"Expected priority to be changed to %d, not %d\n",
110 			thread2_prio + 2, thread2_data);
111 
112 	/* Raise the priority of thread2 */
113 	k_thread_priority_set(thread2_id, thread2_prio - 2);
114 	k_sem_give(&sem_thread2);
115 	k_sem_take(&sem_thread1, K_FOREVER);
116 	zassert_equal(thread2_data, thread2_prio - 2,
117 			"Expected priority to be changed to %d, not %d\n",
118 			thread2_prio - 2, thread2_data);
119 
120 	/* Restore the priority of thread2 */
121 	k_thread_priority_set(thread2_id, thread2_prio);
122 	k_sem_give(&sem_thread2);
123 	k_sem_take(&sem_thread1, K_FOREVER);
124 	zassert_equal(thread2_data, thread2_prio,
125 			"Expected priority to be changed to %d, not %d\n",
126 			thread2_prio, thread2_data);
127 
128 	k_thread_join(thread2_id, K_FOREVER);
129 }
130 
131 /**
132  * @ingroup kernel_thread_tests
133  * @brief Test changing thread priorities from an ISR
134  *
135  * @details This test verifies that thread priorities can be changed
136  * correctly when invoked from an interrupt service routine (ISR).
137  *
138  * @see k_thread_priority_set(), k_thread_priority_get()
139  */
ZTEST(threads_lifecycle,test_isr_threads_priority_set_)140 ZTEST(threads_lifecycle, test_isr_threads_priority_set_)
141 {
142 	int rv;
143 	int prio = k_thread_priority_get(k_current_get());
144 
145 	/* Lower the priority of the current thread (thread1) */
146 	prio_args.thread = k_current_get();
147 	prio_args.prio = prio + 2;
148 	irq_offload(test_isr, &prio_args);
149 	rv = k_thread_priority_get(k_current_get());
150 	zassert_equal(rv, prio + 2,
151 			"Expected priority to be changed to %d, not %d\n",
152 			prio + 2, rv);
153 
154 	/* Raise the priority of the current thread (thread1) */
155 	prio_args.prio = prio - 2;
156 	irq_offload(test_isr, &prio_args);
157 	rv = k_thread_priority_get(k_current_get());
158 	zassert_equal(rv, prio - 2,
159 			"Expected priority to be changed to %d, not %d\n",
160 			prio - 2, rv);
161 
162 	/* Restore the priority of the current thread (thread1) */
163 	prio_args.prio = prio;
164 	irq_offload(test_isr, &prio_args);
165 	rv = k_thread_priority_get(k_current_get());
166 	zassert_equal(rv, prio,
167 			"Expected priority to be changed to %d, not %d\n",
168 			prio, rv);
169 
170 	/* create thread with lower priority */
171 	int thread2_prio = prio + 1;
172 
173 	k_tid_t thread2_id = k_thread_create(&tdata, tstack, STACK_SIZE,
174 			thread2_set_prio_test,
175 			NULL, NULL, NULL, thread2_prio, 0,
176 			K_NO_WAIT);
177 
178 	/* Lower the priority of thread2 */
179 	prio_args.thread = thread2_id;
180 	prio_args.prio = thread2_prio + 2;
181 	irq_offload(test_isr, &prio_args);
182 	k_sem_give(&sem_thread2);
183 	k_sem_take(&sem_thread1, K_FOREVER);
184 	zassert_equal(thread2_data, thread2_prio + 2,
185 			"Expected priority to be changed to %d, not %d\n",
186 			thread2_prio + 2, thread2_data);
187 
188 	/* Raise the priority of thread2 */
189 	prio_args.prio = thread2_prio - 2;
190 	irq_offload(test_isr, &prio_args);
191 	k_sem_give(&sem_thread2);
192 	k_sem_take(&sem_thread1, K_FOREVER);
193 	zassert_equal(thread2_data, thread2_prio - 2,
194 			"Expected priority to be changed to %d, not %d\n",
195 			thread2_prio - 2, thread2_data);
196 
197 	/* Restore the priority of thread2 */
198 	prio_args.prio = thread2_prio;
199 	irq_offload(test_isr, &prio_args);
200 	k_sem_give(&sem_thread2);
201 	k_sem_take(&sem_thread1, K_FOREVER);
202 	zassert_equal(thread2_data, thread2_prio,
203 			"Expected priority to be changed to %d, not %d\n",
204 			thread2_prio, thread2_data);
205 	k_thread_join(thread2_id, K_FOREVER);
206 }
207