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