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