1 /*
2 * Copyright (c) 2016 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include "test_msgq.h"
8
9 /**TESTPOINT: init via K_MSGQ_DEFINE*/
10 K_MSGQ_DEFINE(kmsgq, MSG_SIZE, MSGQ_LEN, 4);
11 K_MSGQ_DEFINE(kmsgq_test_alloc, MSG_SIZE, MSGQ_LEN, 4);
12 struct k_msgq msgq;
13 struct k_msgq msgq1;
14 K_THREAD_STACK_DEFINE(tstack, STACK_SIZE);
15 K_THREAD_STACK_DEFINE(tstack1, STACK_SIZE);
16 K_THREAD_STACK_DEFINE(tstack2, STACK_SIZE);
17 struct k_thread tdata;
18 struct k_thread tdata1;
19 struct k_thread tdata2;
20 static ZTEST_BMEM char __aligned(4) tbuffer[MSG_SIZE * MSGQ_LEN];
21 static ZTEST_DMEM char __aligned(4) tbuffer1[MSG_SIZE];
22 static ZTEST_DMEM uint32_t data[MSGQ_LEN] = { MSG0, MSG1 };
23 struct k_sem end_sema;
24
put_msgq(struct k_msgq * pmsgq)25 static void put_msgq(struct k_msgq *pmsgq)
26 {
27 int ret;
28 uint32_t read_data;
29
30 for (int i = 0; i < MSGQ_LEN; i++) {
31 ret = k_msgq_put(pmsgq, (void *)&data[i], K_NO_WAIT);
32 zassert_equal(ret, 0, NULL);
33
34 /**TESTPOINT: Check if k_msgq_peek reads msgq
35 * in FIFO manner.
36 * Everytime msg is enqueued, msg read should
37 * always be the first message
38 */
39 zassert_equal(k_msgq_peek(pmsgq, &read_data), 0, NULL);
40 zassert_equal(read_data, data[0], NULL);
41
42 /**TESTPOINT: msgq free get*/
43 zassert_equal(k_msgq_num_free_get(pmsgq),
44 MSGQ_LEN - 1 - i, NULL);
45 /**TESTPOINT: msgq used get*/
46 zassert_equal(k_msgq_num_used_get(pmsgq), i + 1, NULL);
47 }
48 }
49
get_msgq(struct k_msgq * pmsgq)50 static void get_msgq(struct k_msgq *pmsgq)
51 {
52 uint32_t rx_data, read_data;
53 int ret;
54
55 for (int i = 0; i < MSGQ_LEN; i++) {
56 zassert_equal(k_msgq_peek(pmsgq, &read_data), 0, NULL);
57
58 ret = k_msgq_get(pmsgq, &rx_data, K_FOREVER);
59 zassert_equal(ret, 0, NULL);
60 zassert_equal(rx_data, data[i], NULL);
61
62 /**TESTPOINT: Check if msg read is the msg deleted*/
63 zassert_equal(read_data, rx_data, NULL);
64 /**TESTPOINT: msgq free get*/
65 zassert_equal(k_msgq_num_free_get(pmsgq), i + 1, NULL);
66 /**TESTPOINT: msgq used get*/
67 zassert_equal(k_msgq_num_used_get(pmsgq),
68 MSGQ_LEN - 1 - i, NULL);
69 }
70 }
71
purge_msgq(struct k_msgq * pmsgq)72 static void purge_msgq(struct k_msgq *pmsgq)
73 {
74 uint32_t read_data;
75
76 k_msgq_purge(pmsgq);
77 zassert_equal(k_msgq_num_free_get(pmsgq), MSGQ_LEN, NULL);
78 zassert_equal(k_msgq_num_used_get(pmsgq), 0, NULL);
79 zassert_equal(k_msgq_peek(pmsgq, &read_data), -ENOMSG, NULL);
80 }
81
tisr_entry(const void * p)82 static void tisr_entry(const void *p)
83 {
84 put_msgq((struct k_msgq *)p);
85 }
86
thread_entry(void * p1,void * p2,void * p3)87 static void thread_entry(void *p1, void *p2, void *p3)
88 {
89 get_msgq((struct k_msgq *)p1);
90 k_sem_give(&end_sema);
91 }
92
msgq_thread(struct k_msgq * pmsgq)93 static void msgq_thread(struct k_msgq *pmsgq)
94 {
95 /**TESTPOINT: thread-thread data passing via message queue*/
96 put_msgq(pmsgq);
97 k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE,
98 thread_entry, pmsgq, NULL, NULL,
99 K_PRIO_PREEMPT(0),
100 K_USER | K_INHERIT_PERMS, K_NO_WAIT);
101 k_sem_take(&end_sema, K_FOREVER);
102 k_thread_abort(tid);
103
104 /**TESTPOINT: msgq purge*/
105 purge_msgq(pmsgq);
106 }
107
thread_entry_overflow(void * p1,void * p2,void * p3)108 static void thread_entry_overflow(void *p1, void *p2, void *p3)
109 {
110 int ret;
111
112 uint32_t rx_buf[MSGQ_LEN];
113
114 ret = k_msgq_get(p1, &rx_buf[0], K_FOREVER);
115
116 zassert_equal(ret, 0, NULL);
117
118 ret = k_msgq_get(p1, &rx_buf[1], K_FOREVER);
119
120 zassert_equal(ret, 0, NULL);
121
122 k_sem_give(&end_sema);
123 }
124
msgq_thread_overflow(struct k_msgq * pmsgq)125 static void msgq_thread_overflow(struct k_msgq *pmsgq)
126 {
127 int ret;
128
129 ret = k_msgq_put(pmsgq, (void *)&data[0], K_FOREVER);
130
131 zassert_equal(ret, 0, NULL);
132
133 /**TESTPOINT: thread-thread data passing via message queue*/
134 k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE,
135 thread_entry_overflow, pmsgq, NULL, NULL,
136 K_PRIO_PREEMPT(0),
137 K_USER | K_INHERIT_PERMS, K_NO_WAIT);
138
139 ret = k_msgq_put(pmsgq, (void *)&data[1], K_FOREVER);
140
141 zassert_equal(ret, 0, NULL);
142
143 k_sem_take(&end_sema, K_FOREVER);
144 k_thread_abort(tid);
145
146 /**TESTPOINT: msgq purge*/
147 k_msgq_purge(pmsgq);
148 }
149
msgq_isr(struct k_msgq * pmsgq)150 static void msgq_isr(struct k_msgq *pmsgq)
151 {
152 /**TESTPOINT: thread-isr data passing via message queue*/
153 irq_offload(tisr_entry, (const void *)pmsgq);
154 get_msgq(pmsgq);
155
156 /**TESTPOINT: msgq purge*/
157 purge_msgq(pmsgq);
158 }
159
thread_entry_get_data(void * p1,void * p2,void * p3)160 static void thread_entry_get_data(void *p1, void *p2, void *p3)
161 {
162 static uint32_t rx_buf[MSGQ_LEN];
163 int i = 0;
164
165 while (k_msgq_get(p1, &rx_buf[i], K_NO_WAIT) != 0) {
166 ++i;
167 }
168
169 k_sem_give(&end_sema);
170 }
171
pend_thread_entry(void * p1,void * p2,void * p3)172 static void pend_thread_entry(void *p1, void *p2, void *p3)
173 {
174 int ret;
175
176 ret = k_msgq_put(p1, &data[1], TIMEOUT);
177 zassert_equal(ret, 0, NULL);
178 }
179
msgq_thread_data_passing(struct k_msgq * pmsgq)180 static void msgq_thread_data_passing(struct k_msgq *pmsgq)
181 {
182 while (k_msgq_put(pmsgq, &data[0], K_NO_WAIT) != 0) {
183 }
184
185 k_tid_t tid = k_thread_create(&tdata2, tstack2, STACK_SIZE,
186 pend_thread_entry, pmsgq, NULL,
187 NULL, K_PRIO_PREEMPT(0), 0, K_NO_WAIT);
188
189 k_tid_t tid1 = k_thread_create(&tdata1, tstack1, STACK_SIZE,
190 thread_entry_get_data, pmsgq, NULL,
191 NULL, K_PRIO_PREEMPT(1), 0, K_NO_WAIT);
192
193 k_sem_take(&end_sema, K_FOREVER);
194 k_thread_abort(tid);
195 k_thread_abort(tid1);
196
197 /**TESTPOINT: msgq purge*/
198 k_msgq_purge(pmsgq);
199 }
200
get_empty_entry(void * p1,void * p2,void * p3)201 static void get_empty_entry(void *p1, void *p2, void *p3)
202 {
203 int ret;
204 static uint32_t rx_buf[MSGQ_LEN];
205
206 /* make sure there is no message in the queue */
207 ret = k_msgq_peek(p1, rx_buf);
208 zassert_equal(ret, -ENOMSG, "Peek message from empty queue");
209
210 ret = k_msgq_get(p1, rx_buf, K_NO_WAIT);
211 zassert_equal(ret, -ENOMSG, "Got message from empty queue");
212
213 /* blocked to TIMEOUT */
214 ret = k_msgq_get(p1, rx_buf, TIMEOUT);
215 zassert_equal(ret, -EAGAIN, "Got message from empty queue");
216
217 k_sem_give(&end_sema);
218 /* blocked forever */
219 ret = k_msgq_get(p1, rx_buf, K_FOREVER);
220 zassert_equal(ret, 0, NULL);
221 }
222
put_full_entry(void * p1,void * p2,void * p3)223 static void put_full_entry(void *p1, void *p2, void *p3)
224 {
225 int ret;
226
227 /* make sure the queue is full */
228 zassert_equal(k_msgq_num_free_get(p1), 0, NULL);
229 zassert_equal(k_msgq_num_used_get(p1), 1, NULL);
230
231 ret = k_msgq_put(p1, &data[1], K_NO_WAIT);
232 zassert_equal(ret, -ENOMSG, "Put message to full queue");
233
234 /* blocked to TIMEOUT */
235 ret = k_msgq_put(p1, &data[1], TIMEOUT);
236 zassert_equal(ret, -EAGAIN, "Put message to full queue");
237
238 k_sem_give(&end_sema);
239 /* blocked forever */
240 ret = k_msgq_put(p1, &data[1], K_FOREVER);
241 zassert_equal(ret, 0, NULL);
242 }
243
244 /**
245 * @addtogroup kernel_message_queue_tests
246 * @{
247 */
248
249 /**
250 * @brief Test thread to thread data passing via message queue
251 * @see k_msgq_init(), k_msgq_get(), k_msgq_put(), k_msgq_purge()
252 */
test_msgq_thread(void)253 void test_msgq_thread(void)
254 {
255 int ret;
256
257 /**TESTPOINT: init via k_msgq_init*/
258 k_msgq_init(&msgq, tbuffer, MSG_SIZE, MSGQ_LEN);
259 ret = k_sem_init(&end_sema, 0, 1);
260 zassert_equal(ret, 0, NULL);
261
262 msgq_thread(&msgq);
263 msgq_thread(&kmsgq);
264 }
265
266 /**
267 * @brief Test thread to thread data passing via message queue
268 * @see k_msgq_init(), k_msgq_get(), k_msgq_put(), k_msgq_purge()
269 */
test_msgq_thread_overflow(void)270 void test_msgq_thread_overflow(void)
271 {
272 int ret;
273
274 /**TESTPOINT: init via k_msgq_init*/
275 k_msgq_init(&msgq, tbuffer, MSG_SIZE, 1);
276 ret = k_sem_init(&end_sema, 0, 1);
277 zassert_equal(ret, 0, NULL);
278
279 msgq_thread_overflow(&msgq);
280 msgq_thread_overflow(&kmsgq);
281 }
282
283 #ifdef CONFIG_USERSPACE
284 /**
285 * @brief Test user thread to kernel thread data passing via message queue
286 * @see k_msgq_alloc_init(), k_msgq_get(), k_msgq_put(), k_msgq_purge()
287 */
test_msgq_user_thread(void)288 void test_msgq_user_thread(void)
289 {
290 struct k_msgq *q;
291 int ret;
292
293 q = k_object_alloc(K_OBJ_MSGQ);
294 zassert_not_null(q, "couldn't alloc message queue");
295 zassert_false(k_msgq_alloc_init(q, MSG_SIZE, MSGQ_LEN), NULL);
296 ret = k_sem_init(&end_sema, 0, 1);
297 zassert_equal(ret, 0, NULL);
298
299 msgq_thread(q);
300 }
301
302 /**
303 * @brief Test thread to thread data passing via message queue
304 * @see k_msgq_alloc_init(), k_msgq_get(), k_msgq_put(), k_msgq_purge()
305 */
test_msgq_user_thread_overflow(void)306 void test_msgq_user_thread_overflow(void)
307 {
308 struct k_msgq *q;
309 int ret;
310
311 q = k_object_alloc(K_OBJ_MSGQ);
312 zassert_not_null(q, "couldn't alloc message queue");
313 zassert_false(k_msgq_alloc_init(q, MSG_SIZE, 1), NULL);
314 ret = k_sem_init(&end_sema, 0, 1);
315 zassert_equal(ret, 0, NULL);
316
317 msgq_thread_overflow(q);
318 }
319 #endif /* CONFIG_USERSPACE */
320
321 /**
322 * @brief Test thread to isr data passing via message queue
323 * @see k_msgq_init(), k_msgq_get(), k_msgq_put(), k_msgq_purge()
324 */
test_msgq_isr(void)325 void test_msgq_isr(void)
326 {
327 static struct k_msgq stack_msgq;
328
329 /**TESTPOINT: init via k_msgq_init*/
330 k_msgq_init(&stack_msgq, tbuffer, MSG_SIZE, MSGQ_LEN);
331
332 msgq_isr(&stack_msgq);
333 msgq_isr(&kmsgq);
334 }
335
336 /**
337 * @brief Test pending writer in msgq
338 * @see k_msgq_init(), k_msgq_get(), k_msgq_put(), k_msgq_purge()
339 */
test_msgq_pend_thread(void)340 void test_msgq_pend_thread(void)
341 {
342 int ret;
343
344 k_msgq_init(&msgq1, tbuffer1, MSG_SIZE, 1);
345 ret = k_sem_init(&end_sema, 0, 1);
346 zassert_equal(ret, 0, NULL);
347
348 msgq_thread_data_passing(&msgq1);
349 }
350
351 /**
352 * @brief Test k_msgq_alloc_init()
353 * @details Initialization and buffer allocation for msgq from resource
354 * pool with various parameters
355 * @see k_msgq_alloc_init(), k_msgq_cleanup()
356 */
test_msgq_alloc(void)357 void test_msgq_alloc(void)
358 {
359 int ret;
360
361 k_msgq_alloc_init(&kmsgq_test_alloc, MSG_SIZE, MSGQ_LEN);
362 msgq_isr(&kmsgq_test_alloc);
363 k_msgq_cleanup(&kmsgq_test_alloc);
364
365 /** Requesting buffer allocation from the test pool.*/
366 ret = k_msgq_alloc_init(&kmsgq_test_alloc, MSG_SIZE * 128, MSGQ_LEN);
367 zassert_true(ret == -ENOMEM,
368 "resource pool is smaller then requested buffer");
369
370 /* Requesting a huge size of MSG to validate overflow*/
371 ret = k_msgq_alloc_init(&kmsgq_test_alloc, OVERFLOW_SIZE_MSG, MSGQ_LEN);
372 zassert_true(ret == -EINVAL, "Invalid request");
373 }
374
375 /**
376 * @brief Get message from an empty queue
377 *
378 * @details
379 * - A thread get message from an empty message queue will get a -ENOMSG if
380 * timeout is set to K_NO_WAIT
381 * - A thread get message from an empty message queue will be blocked if timeout
382 * is set to a positive value or K_FOREVER
383 *
384 * @see k_msgq_get()
385 */
test_msgq_empty(void)386 void test_msgq_empty(void)
387 {
388 int pri = k_thread_priority_get(k_current_get()) - 1;
389 int ret;
390
391 k_msgq_init(&msgq1, tbuffer1, MSG_SIZE, 1);
392 ret = k_sem_init(&end_sema, 0, 1);
393 zassert_equal(ret, 0, NULL);
394
395 k_tid_t tid = k_thread_create(&tdata2, tstack2, STACK_SIZE,
396 get_empty_entry, &msgq1, NULL,
397 NULL, pri, 0, K_NO_WAIT);
398
399 k_sem_take(&end_sema, K_FOREVER);
400 /* that getting thread is being blocked now */
401 zassert_equal(tid->base.thread_state, _THREAD_PENDING, NULL);
402 /* since there is a thread is waiting for message, this queue
403 * can't be cleanup
404 */
405 ret = k_msgq_cleanup(&msgq1);
406 zassert_equal(ret, -EBUSY, NULL);
407
408 /* put a message to wake that getting thread */
409 ret = k_msgq_put(&msgq1, &data[0], K_NO_WAIT);
410 zassert_equal(ret, 0, NULL);
411
412 k_thread_abort(tid);
413 }
414
415 /**
416 * @brief Put message to a full queue
417 *
418 * @details
419 * - A thread put message to a full message queue will get a -ENOMSG if
420 * timeout is set to K_NO_WAIT
421 * - A thread put message to a full message queue will be blocked if timeout
422 * is set to a positive value or K_FOREVER
423 *
424 * @see k_msgq_put()
425 */
test_msgq_full(void)426 void test_msgq_full(void)
427 {
428 int pri = k_thread_priority_get(k_current_get()) - 1;
429 int ret;
430
431 k_msgq_init(&msgq1, tbuffer1, MSG_SIZE, 1);
432 ret = k_sem_init(&end_sema, 0, 1);
433 zassert_equal(ret, 0, NULL);
434
435 ret = k_msgq_put(&msgq1, &data[0], K_NO_WAIT);
436 zassert_equal(ret, 0, NULL);
437
438 k_tid_t tid = k_thread_create(&tdata2, tstack2, STACK_SIZE,
439 put_full_entry, &msgq1, NULL,
440 NULL, pri, 0, K_NO_WAIT);
441 k_sem_take(&end_sema, K_FOREVER);
442 /* that putting thread is being blocked now */
443 zassert_equal(tid->base.thread_state, _THREAD_PENDING, NULL);
444 k_thread_abort(tid);
445 }
446
447 /**
448 * @}
449 */
450