1 /*
2 * Copyright (c) 2016 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/ztest.h>
8
9 #include "tests_thread_apis.h"
10
11 static ZTEST_BMEM int last_prio;
12
thread_entry(void * p1,void * p2,void * p3)13 static void thread_entry(void *p1, void *p2, void *p3)
14 {
15 last_prio = k_thread_priority_get(k_current_get());
16 }
17
threads_suspend_resume(int prio)18 static void threads_suspend_resume(int prio)
19 {
20 /* set current thread */
21 last_prio = prio;
22 k_thread_priority_set(k_current_get(), last_prio);
23
24 /* create thread with lower priority */
25 int create_prio = last_prio + 1;
26
27 k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE,
28 thread_entry, NULL, NULL, NULL,
29 create_prio, K_USER, K_NO_WAIT);
30 /* checkpoint: suspend current thread */
31 k_thread_suspend(tid);
32 k_msleep(100);
33 /* checkpoint: created thread shouldn't be executed after suspend */
34 zassert_false(last_prio == create_prio);
35 k_thread_resume(tid);
36 k_msleep(100);
37 /* checkpoint: created thread should be executed after resume */
38 zassert_true(last_prio == create_prio);
39 }
40
41 /*test cases*/
42
43 /**
44 * @ingroup kernel_thread_tests
45 * @brief Check the suspend and resume functionality in
46 * a cooperative thread
47 *
48 * @details Create a thread with the priority lower than the current
49 * thread which is cooperative and suspend it, make sure it doesn't
50 * gets scheduled, and resume and check if the entry function is executed.
51 *
52 * @see k_thread_suspend(), k_thread_resume()
53 */
ZTEST(threads_lifecycle_1cpu,test_threads_suspend_resume_cooperative)54 ZTEST(threads_lifecycle_1cpu, test_threads_suspend_resume_cooperative)
55 {
56 threads_suspend_resume(-2);
57 }
58
59 /**
60 * @ingroup kernel_thread_tests
61 * @brief Check the suspend and resume functionality in
62 * preemptive thread
63 *
64 * @details Create a thread with the priority lower than the current
65 * thread which is preemptive and suspend it, make sure it doesn't gets
66 * scheduled, and resume and check if the entry function is executed.
67 *
68 * @see k_thread_suspend(), k_thread_resume()
69 */
ZTEST_USER(threads_lifecycle,test_threads_suspend_resume_preemptible)70 ZTEST_USER(threads_lifecycle, test_threads_suspend_resume_preemptible)
71 {
72 threads_suspend_resume(1);
73 }
74
75 static bool after_suspend;
76
suspend_myself(void * arg0,void * arg1,void * arg2)77 void suspend_myself(void *arg0, void *arg1, void *arg2)
78 {
79 ARG_UNUSED(arg0);
80 ARG_UNUSED(arg1);
81 ARG_UNUSED(arg2);
82 k_thread_suspend(k_current_get());
83 after_suspend = true;
84 }
85
86 /**
87 * @ingroup kernel_thread_tests
88 *
89 * @brief Check that k_thread_suspend() is a schedule point when
90 * called on the current thread.
91 */
ZTEST(threads_lifecycle,test_threads_suspend)92 ZTEST(threads_lifecycle, test_threads_suspend)
93 {
94 after_suspend = false;
95
96 k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE,
97 suspend_myself, NULL, NULL, NULL,
98 0, K_USER, K_NO_WAIT);
99
100 /* Give the thread a chance to start and verify that it
101 * stopped executing after suspending itself.
102 */
103 k_msleep(100);
104 zassert_false(after_suspend, "thread woke up unexpectedly");
105
106 k_thread_abort(tid);
107 }
108
sleep_suspended(void * arg0,void * arg1,void * arg2)109 void sleep_suspended(void *arg0, void *arg1, void *arg2)
110 {
111 ARG_UNUSED(arg0);
112 ARG_UNUSED(arg1);
113 ARG_UNUSED(arg2);
114
115 /* Sleep a half second, then set the flag after we wake up.
116 * If we are suspended, the wakeup should not occur
117 */
118 k_msleep(100);
119 after_suspend = true;
120 }
121
122 /**
123 * @ingroup kernel_thread_tests
124 * @brief Check that k_thread_suspend() cancels a preexisting thread timeout
125 *
126 * @details Suspended threads should not wake up unexpectedly if they
127 * happened to have been sleeping when suspended.
128 */
ZTEST(threads_lifecycle,test_threads_suspend_timeout)129 ZTEST(threads_lifecycle, test_threads_suspend_timeout)
130 {
131 after_suspend = false;
132
133 k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE,
134 sleep_suspended, NULL, NULL, NULL,
135 0, K_USER, K_NO_WAIT);
136
137 k_msleep(50);
138 k_thread_suspend(tid);
139
140 /* Give the timer long enough to expire, and verify that it
141 * has not (i.e. that the thread didn't wake up, because it
142 * has been suspended)
143 */
144 k_msleep(200);
145 zassert_false(after_suspend, "thread woke up unexpectedly");
146
147 k_thread_abort(tid);
148 }
149
150 /**
151 * @ingroup kernel_thread_tests
152 * @brief Check resume an unsuspend thread
153 *
154 * @details Use k_thread_state_str() to get thread state.
155 * Resume an unsuspend thread will not change the thread state.
156 */
ZTEST(threads_lifecycle,test_resume_unsuspend_thread)157 ZTEST(threads_lifecycle, test_resume_unsuspend_thread)
158 {
159 char buffer[32];
160 const char *str;
161 k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE,
162 thread_entry, NULL, NULL, NULL,
163 0, K_USER, K_NO_WAIT);
164
165
166 /* Resume an unsuspend thread will not change the thread state. */
167 str = k_thread_state_str(tid, buffer, sizeof(buffer));
168 zassert_str_equal(str, "queued");
169 k_thread_resume(tid);
170 str = k_thread_state_str(tid, buffer, sizeof(buffer));
171 zassert_str_equal(str, "queued");
172
173 /* suspend created thread */
174 k_thread_suspend(tid);
175 str = k_thread_state_str(tid, buffer, sizeof(buffer));
176 zassert_str_equal(str, "suspended");
177
178 /* Resume an suspend thread will make it to be next eligible.*/
179 k_thread_resume(tid);
180 str = k_thread_state_str(tid, buffer, sizeof(buffer));
181 zassert_str_equal(str, "queued");
182 k_thread_abort(tid);
183 }
184