1 /*
2 * Copyright (c) 2016 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include "test_sched.h"
8 #include <ksched.h>
9
10 #define THREAD_NUM 4
11
12 static struct k_thread tdata_prio[THREAD_NUM];
13 static struct k_thread tdata;
14 static int last_prio;
15 static uint8_t tid_num[4];
16 static struct k_sem sync_sema;
17
18
thread_entry(void * p1,void * p2,void * p3)19 static void thread_entry(void *p1, void *p2, void *p3)
20 {
21 last_prio = k_thread_priority_get(k_current_get());
22 }
23
thread_entry_prio(void * p1,void * p2,void * p3)24 static void thread_entry_prio(void *p1, void *p2, void *p3)
25 {
26 static int i;
27
28 k_sem_take(&sync_sema, K_MSEC(100));
29
30 tid_num[i++] = POINTER_TO_INT(p1);
31 }
32
33
34 /* test cases */
35
36 /**
37 * @brief Validate that the cooperative thread will
38 * not be preempted
39 *
40 * @details Create a cooperative thread with priority higher
41 * than the current cooperative thread. Make sure that the higher
42 * priority thread will not preempt the lower priority cooperative
43 * thread.
44 *
45 * @ingroup kernel_sched_tests
46 */
ZTEST(threads_scheduling,test_priority_cooperative)47 ZTEST(threads_scheduling, test_priority_cooperative)
48 {
49 int old_prio = k_thread_priority_get(k_current_get());
50
51 /* set current thread to a negative priority */
52 last_prio = -1;
53 k_thread_priority_set(k_current_get(), last_prio);
54
55 /* spawn thread with higher priority */
56 int spawn_prio = last_prio - 1;
57
58 k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE,
59 thread_entry, NULL, NULL, NULL,
60 spawn_prio, 0, K_NO_WAIT);
61 /* checkpoint: current thread shouldn't preempted by higher thread */
62 zassert_true(last_prio == k_thread_priority_get(k_current_get()));
63 k_sleep(K_MSEC(100));
64 /* checkpoint: spawned thread get executed */
65 zassert_true(last_prio == spawn_prio);
66 k_thread_abort(tid);
67
68 /* restore environment */
69 k_thread_priority_set(k_current_get(), old_prio);
70 }
71
72 /**
73 * @brief Validate preemptiveness of preemptive thread
74 *
75 * @details Create a preemptive thread which is of priority
76 * lower than current thread. Current thread is made has preemptive.
77 * Make sure newly created thread is not preempted. Now create a
78 * preemptive thread which is of priority higher than current
79 * thread. Make sure newly created thread is preempted
80 *
81 * @ingroup kernel_sched_tests
82 */
ZTEST(threads_scheduling,test_priority_preemptible)83 ZTEST(threads_scheduling, test_priority_preemptible)
84 {
85 int old_prio = k_thread_priority_get(k_current_get());
86
87 /* set current thread to a non-negative priority */
88 last_prio = 2;
89 k_thread_priority_set(k_current_get(), last_prio);
90
91 int spawn_prio = last_prio - 1;
92
93 k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE,
94 thread_entry, NULL, NULL, NULL,
95 spawn_prio, 0, K_NO_WAIT);
96 /* checkpoint: thread is preempted by higher thread */
97 zassert_true(last_prio == spawn_prio);
98
99 k_sleep(K_MSEC(100));
100 k_thread_abort(tid);
101
102 spawn_prio = last_prio + 1;
103 tid = k_thread_create(&tdata, tstack, STACK_SIZE,
104 thread_entry, NULL, NULL, NULL,
105 spawn_prio, 0, K_NO_WAIT);
106 /* checkpoint: thread is not preempted by lower thread */
107 zassert_false(last_prio == spawn_prio);
108 k_thread_abort(tid);
109
110 /* restore environment */
111 k_thread_priority_set(k_current_get(), old_prio);
112 }
113
114 /**
115 * @brief Validate scheduling sequence of preemptive threads with start delay
116 *
117 * @details Create four preemptive threads which are of priority
118 * higher than current thread. Make sure that the highest priority
119 * and longest waiting thread is scheduled first.
120 *
121 * @ingroup kernel_sched_tests
122 */
ZTEST(threads_scheduling_1cpu,test_priority_preemptible_wait_prio)123 ZTEST(threads_scheduling_1cpu, test_priority_preemptible_wait_prio)
124 {
125 int old_prio = k_thread_priority_get(k_current_get());
126 k_tid_t tid[THREAD_NUM];
127 uint8_t tid_chk[4] = { 0, 1, 2, 3 };
128
129 k_sem_init(&sync_sema, 0, THREAD_NUM);
130
131 /* Ensure that this code starts running at the start of a system tick */
132 k_usleep(1);
133
134 /* set current thread to a non-negative priority */
135 last_prio = K_PRIO_PREEMPT(2);
136 k_thread_priority_set(k_current_get(), last_prio);
137
138 /* the highest-priority thread that has waited the longest */
139 tid[0] = k_thread_create(&tdata_prio[0], tstacks[0], STACK_SIZE,
140 thread_entry_prio, INT_TO_POINTER(0), NULL, NULL,
141 K_PRIO_PREEMPT(0), 0, K_MSEC(10));
142 /* the highest-priority thread that has waited the shorter */
143 tid[1] = k_thread_create(&tdata_prio[1], tstacks[1], STACK_SIZE,
144 thread_entry_prio, INT_TO_POINTER(1), NULL, NULL,
145 K_PRIO_PREEMPT(0), 0, K_MSEC(20));
146 /* the lowest-priority thread that has waited longest */
147 tid[2] = k_thread_create(&tdata_prio[2], tstacks[2], STACK_SIZE,
148 thread_entry_prio, INT_TO_POINTER(2), NULL, NULL,
149 K_PRIO_PREEMPT(1), 0, K_MSEC(10));
150 /* the lowest-priority thread that has waited shorter */
151 tid[3] = k_thread_create(&tdata_prio[3], tstacks[3], STACK_SIZE,
152 thread_entry_prio, INT_TO_POINTER(3), NULL, NULL,
153 K_PRIO_PREEMPT(1), 0, K_MSEC(20));
154
155 /* relinquish CPU for above threads to start */
156 k_sleep(K_MSEC(30));
157
158 for (int i = 0; i < THREAD_NUM; i++) {
159 k_sem_give(&sync_sema);
160 }
161
162 zassert_true((memcmp(tid_num, tid_chk, 4) == 0),
163 "scheduling priority failed");
164
165 /* test case tear down */
166 for (int i = 0; i < THREAD_NUM; i++) {
167 k_thread_abort(tid[i]);
168 }
169
170 /* restore environment */
171 k_thread_priority_set(k_current_get(), old_prio);
172 }
173
174 extern void idle(void *p1, void *p2, void *p3);
175
176 /**
177 * Validate checking priority values
178 *
179 * Our test cases don't cover every outcome of whether a priority is valid,
180 * do so here.
181 *
182 * @ingroup kernel_sched_tests
183 */
ZTEST(threads_scheduling,test_bad_priorities)184 ZTEST(threads_scheduling, test_bad_priorities)
185 {
186 struct prio_test {
187 int prio;
188 void *entry;
189 bool result;
190 } testcases[] = {
191 { K_IDLE_PRIO, idle, true },
192 { K_IDLE_PRIO, NULL, false },
193 { K_HIGHEST_APPLICATION_THREAD_PRIO - 1, NULL, false },
194 { K_LOWEST_APPLICATION_THREAD_PRIO + 1, NULL, false },
195 { K_HIGHEST_APPLICATION_THREAD_PRIO, NULL, true },
196 { K_LOWEST_APPLICATION_THREAD_PRIO, NULL, true },
197 { CONFIG_MAIN_THREAD_PRIORITY, NULL, true }
198 };
199
200 for (int i = 0; i < ARRAY_SIZE(testcases); i++) {
201 zassert_equal(_is_valid_prio(testcases[i].prio,
202 testcases[i].entry),
203 testcases[i].result, "failed check %d", i);
204 /* XXX why are these even separate APIs? */
205 zassert_equal(Z_VALID_PRIO(testcases[i].prio,
206 testcases[i].entry),
207 testcases[i].result, "failed check %d", i);
208 }
209 }
210