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);
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);
40 zassert_equal(read_data, data[0]);
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);
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);
57
58 ret = k_msgq_get(pmsgq, &rx_data, K_FOREVER);
59 zassert_equal(ret, 0);
60 zassert_equal(rx_data, data[i]);
61
62 /**TESTPOINT: Check if msg read is the msg deleted*/
63 zassert_equal(read_data, rx_data);
64 /**TESTPOINT: msgq free get*/
65 zassert_equal(k_msgq_num_free_get(pmsgq), i + 1);
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);
78 zassert_equal(k_msgq_num_used_get(pmsgq), 0);
79 zassert_equal(k_msgq_peek(pmsgq, &read_data), -ENOMSG);
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);
117
118 ret = k_msgq_get(p1, &rx_buf[1], K_FOREVER);
119
120 zassert_equal(ret, 0);
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);
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);
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);
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);
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);
229 zassert_equal(k_msgq_num_used_get(p1), 1);
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);
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 */
ZTEST(msgq_api_1cpu,test_msgq_thread)253 ZTEST(msgq_api_1cpu, test_msgq_thread)
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);
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 */
ZTEST(msgq_api,test_msgq_thread_overflow)270 ZTEST(msgq_api, test_msgq_thread_overflow)
271 {
272 int ret;
273
274 /**TESTPOINT: init via k_msgq_init*/
275 k_msgq_init(&msgq, tbuffer, MSG_SIZE, 2);
276 ret = k_sem_init(&end_sema, 0, 1);
277 zassert_equal(ret, 0);
278
279 ret = k_msgq_put(&msgq, (void *)&data[0], K_FOREVER);
280 zassert_equal(ret, 0);
281
282 msgq_thread_overflow(&msgq);
283 msgq_thread_overflow(&kmsgq);
284
285 /*verify the write pointer not reset to the buffer start*/
286 zassert_false(msgq.write_ptr == msgq.buffer_start,
287 "Invalid add operation of message queue");
288 }
289
290 #ifdef CONFIG_USERSPACE
291 /**
292 * @brief Test user thread to kernel thread data passing via message queue
293 * @see k_msgq_alloc_init(), k_msgq_get(), k_msgq_put(), k_msgq_purge()
294 */
ZTEST_USER(msgq_api,test_msgq_user_thread)295 ZTEST_USER(msgq_api, test_msgq_user_thread)
296 {
297 struct k_msgq *q;
298 int ret;
299
300 q = k_object_alloc(K_OBJ_MSGQ);
301 zassert_not_null(q, "couldn't alloc message queue");
302 zassert_false(k_msgq_alloc_init(q, MSG_SIZE, MSGQ_LEN));
303 ret = k_sem_init(&end_sema, 0, 1);
304 zassert_equal(ret, 0);
305
306 msgq_thread(q);
307 }
308
309 /**
310 * @brief Test thread to thread data passing via message queue
311 * @see k_msgq_alloc_init(), k_msgq_get(), k_msgq_put(), k_msgq_purge()
312 */
ZTEST_USER(msgq_api,test_msgq_user_thread_overflow)313 ZTEST_USER(msgq_api, test_msgq_user_thread_overflow)
314 {
315 struct k_msgq *q;
316 int ret;
317
318 q = k_object_alloc(K_OBJ_MSGQ);
319 zassert_not_null(q, "couldn't alloc message queue");
320 zassert_false(k_msgq_alloc_init(q, MSG_SIZE, 1));
321 ret = k_sem_init(&end_sema, 0, 1);
322 zassert_equal(ret, 0);
323
324 msgq_thread_overflow(q);
325 }
326 #endif /* CONFIG_USERSPACE */
327
328 /**
329 * @brief Test thread to isr data passing via message queue
330 * @see k_msgq_init(), k_msgq_get(), k_msgq_put(), k_msgq_purge()
331 */
ZTEST(msgq_api,test_msgq_isr)332 ZTEST(msgq_api, test_msgq_isr)
333 {
334 static struct k_msgq stack_msgq;
335
336 /**TESTPOINT: init via k_msgq_init*/
337 k_msgq_init(&stack_msgq, tbuffer, MSG_SIZE, MSGQ_LEN);
338
339 msgq_isr(&stack_msgq);
340 msgq_isr(&kmsgq);
341 }
342
343 /**
344 * @brief Test pending writer in msgq
345 * @see k_msgq_init(), k_msgq_get(), k_msgq_put(), k_msgq_purge()
346 */
ZTEST(msgq_api_1cpu,test_msgq_pend_thread)347 ZTEST(msgq_api_1cpu, test_msgq_pend_thread)
348 {
349 int ret;
350
351 k_msgq_init(&msgq1, tbuffer1, MSG_SIZE, 1);
352 ret = k_sem_init(&end_sema, 0, 1);
353 zassert_equal(ret, 0);
354
355 msgq_thread_data_passing(&msgq1);
356 }
357
358 /**
359 * @brief Test k_msgq_alloc_init()
360 * @details Initialization and buffer allocation for msgq from resource
361 * pool with various parameters
362 * @see k_msgq_alloc_init(), k_msgq_cleanup()
363 */
ZTEST(msgq_api,test_msgq_alloc)364 ZTEST(msgq_api, test_msgq_alloc)
365 {
366 int ret;
367
368 k_msgq_alloc_init(&kmsgq_test_alloc, MSG_SIZE, MSGQ_LEN);
369 msgq_isr(&kmsgq_test_alloc);
370 k_msgq_cleanup(&kmsgq_test_alloc);
371
372 /** Requesting buffer allocation from the test pool.*/
373 ret = k_msgq_alloc_init(&kmsgq_test_alloc, MSG_SIZE * 128, MSGQ_LEN);
374 zassert_true(ret == -ENOMEM,
375 "resource pool is smaller then requested buffer");
376
377 /* Requesting a huge size of MSG to validate overflow*/
378 ret = k_msgq_alloc_init(&kmsgq_test_alloc, OVERFLOW_SIZE_MSG, MSGQ_LEN);
379 zassert_true(ret == -EINVAL, "Invalid request");
380 }
381
382 /**
383 * @brief Get message from an empty queue
384 *
385 * @details
386 * - A thread get message from an empty message queue will get a -ENOMSG if
387 * timeout is set to K_NO_WAIT
388 * - A thread get message from an empty message queue will be blocked if timeout
389 * is set to a positive value or K_FOREVER
390 *
391 * @see k_msgq_get()
392 */
ZTEST(msgq_api_1cpu,test_msgq_empty)393 ZTEST(msgq_api_1cpu, test_msgq_empty)
394 {
395 int pri = k_thread_priority_get(k_current_get()) - 1;
396 int ret;
397
398 k_msgq_init(&msgq1, tbuffer1, MSG_SIZE, 1);
399 ret = k_sem_init(&end_sema, 0, 1);
400 zassert_equal(ret, 0);
401
402 k_tid_t tid = k_thread_create(&tdata2, tstack2, STACK_SIZE,
403 get_empty_entry, &msgq1, NULL,
404 NULL, pri, 0, K_NO_WAIT);
405
406 k_sem_take(&end_sema, K_FOREVER);
407 /* that getting thread is being blocked now */
408 zassert_equal(tid->base.thread_state, _THREAD_PENDING);
409 /* since there is a thread is waiting for message, this queue
410 * can't be cleanup
411 */
412 ret = k_msgq_cleanup(&msgq1);
413 zassert_equal(ret, -EBUSY);
414
415 /* put a message to wake that getting thread */
416 ret = k_msgq_put(&msgq1, &data[0], K_NO_WAIT);
417 zassert_equal(ret, 0);
418
419 k_thread_abort(tid);
420 }
421
422 /**
423 * @brief Put message to a full queue
424 *
425 * @details
426 * - A thread put message to a full message queue will get a -ENOMSG if
427 * timeout is set to K_NO_WAIT
428 * - A thread put message to a full message queue will be blocked if timeout
429 * is set to a positive value or K_FOREVER
430 *
431 * @see k_msgq_put()
432 */
ZTEST(msgq_api_1cpu,test_msgq_full)433 ZTEST(msgq_api_1cpu, test_msgq_full)
434 {
435 int pri = k_thread_priority_get(k_current_get()) - 1;
436 int ret;
437
438 k_msgq_init(&msgq1, tbuffer1, MSG_SIZE, 1);
439 ret = k_sem_init(&end_sema, 0, 1);
440 zassert_equal(ret, 0);
441
442 ret = k_msgq_put(&msgq1, &data[0], K_NO_WAIT);
443 zassert_equal(ret, 0);
444
445 k_tid_t tid = k_thread_create(&tdata2, tstack2, STACK_SIZE,
446 put_full_entry, &msgq1, NULL,
447 NULL, pri, 0, K_NO_WAIT);
448 k_sem_take(&end_sema, K_FOREVER);
449 /* that putting thread is being blocked now */
450 zassert_equal(tid->base.thread_state, _THREAD_PENDING);
451 k_thread_abort(tid);
452 }
453
454 /**
455 * @}
456 */
457