1 /*
2 * Copyright (c) 2017 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include "test_queue.h"
8
9 #ifdef CONFIG_USERSPACE
10
11 #define STACK_SIZE (512 + CONFIG_TEST_EXTRA_STACKSIZE)
12 #define LIST_LEN 5
13
14 static K_THREAD_STACK_DEFINE(child_stack, STACK_SIZE);
15 static struct k_thread child_thread;
16 static ZTEST_BMEM struct qdata qdata[LIST_LEN * 2];
17
18 /**
19 * @brief Tests for queue
20 * @defgroup kernel_queue_tests Queues
21 * @ingroup all_tests
22 * @{
23 * @}
24 */
25
26 /* Higher priority than the thread putting stuff in the queue */
child_thread_get(void * p1,void * p2,void * p3)27 void child_thread_get(void *p1, void *p2, void *p3)
28 {
29 struct qdata *qd;
30 struct k_queue *q = p1;
31 struct k_sem *sem = p2;
32
33 zassert_false(k_queue_is_empty(q), NULL);
34 qd = k_queue_peek_head(q);
35 zassert_equal(qd->data, 0, NULL);
36 qd = k_queue_peek_tail(q);
37 zassert_equal(qd->data, (LIST_LEN * 2) - 1,
38 "got %d expected %d", qd->data, (LIST_LEN * 2) - 1);
39
40 for (int i = 0; i < (LIST_LEN * 2); i++) {
41 qd = k_queue_get(q, K_FOREVER);
42
43 zassert_equal(qd->data, i, NULL);
44 if (qd->allocated) {
45 /* snode should never have been touched */
46 zassert_is_null(qd->snode.next, NULL);
47 }
48 }
49
50
51 zassert_true(k_queue_is_empty(q), NULL);
52
53 /* This one gets canceled */
54 qd = k_queue_get(q, K_FOREVER);
55 zassert_is_null(qd, NULL);
56
57 k_sem_give(sem);
58 }
59
60 /**
61 * @brief Verify queue elements and cancel wait from a user thread
62 *
63 * @details The test adds elements to queue and then
64 * verified by the child user thread.
65 * Get data from a empty queue,and use K_FORVER to wait for available
66 * And to cancel wait from current thread.
67 *
68 * @ingroup kernel_queue_tests
69 *
70 * @see k_queue_append(), k_queue_alloc_append(),
71 * k_queue_init(), k_queue_cancel_wait()
72 */
test_queue_supv_to_user(void)73 void test_queue_supv_to_user(void)
74 {
75 /* Supervisor mode will add a bunch of data, some with alloc
76 * and some not
77 */
78
79 struct k_queue *q;
80 struct k_sem *sem;
81
82 q = k_object_alloc(K_OBJ_QUEUE);
83 zassert_not_null(q, "no memory for allocated queue object");
84 k_queue_init(q);
85
86 sem = k_object_alloc(K_OBJ_SEM);
87 zassert_not_null(sem, "no memory for semaphore object");
88 k_sem_init(sem, 0, 1);
89
90 for (int i = 0; i < (LIST_LEN * 2); i = i + 2) {
91 /* Just for test purposes -- not safe to do this in the
92 * real world as user mode shouldn't have any access to the
93 * snode struct
94 */
95 qdata[i].data = i;
96 qdata[i].allocated = false;
97 qdata[i].snode.next = NULL;
98 k_queue_append(q, &qdata[i]);
99
100 qdata[i + 1].data = i + 1;
101 qdata[i + 1].allocated = true;
102 qdata[i + 1].snode.next = NULL;
103 zassert_false(k_queue_alloc_append(q, &qdata[i + 1]), NULL);
104 }
105
106 k_thread_create(&child_thread, child_stack, STACK_SIZE,
107 child_thread_get, q, sem, NULL, K_HIGHEST_THREAD_PRIO,
108 K_USER | K_INHERIT_PERMS, K_NO_WAIT);
109
110 k_yield();
111
112 /* child thread runs until blocking on the last k_queue_get() call */
113 k_queue_cancel_wait(q);
114 k_sem_take(sem, K_FOREVER);
115 }
116
117 /**
118 * @brief verify allocate and feature "Last In, First Out"
119 *
120 * @details Create a new queue
121 * And allocated memory for the queue
122 * Initialize and insert data item in sequence.
123 * Verify the feather "Last in,First out"
124 *
125 * @ingroup kernel_queue_tests
126 *
127 * @see k_queue_alloc_prepend()
128 */
test_queue_alloc_prepend_user(void)129 void test_queue_alloc_prepend_user(void)
130 {
131 struct k_queue *q;
132
133 q = k_object_alloc(K_OBJ_QUEUE);
134 zassert_not_null(q, "no memory for allocated queue object");
135 k_queue_init(q);
136
137 for (int i = 0; i < LIST_LEN * 2; i++) {
138 qdata[i].data = i;
139 zassert_false(k_queue_alloc_prepend(q, &qdata[i]), NULL);
140 }
141
142 for (int i = (LIST_LEN * 2) - 1; i >= 0; i--) {
143 struct qdata *qd;
144
145 qd = k_queue_get(q, K_NO_WAIT);
146 zassert_true(qd != NULL, NULL);
147 zassert_equal(qd->data, i, NULL);
148 }
149 }
150
151 /**
152 * @brief verify feature of queue "First In, First Out"
153 *
154 * @details Create a new queue
155 * And allocated memory for the queue
156 * Initialize and insert data item in sequence.
157 * Verify the feather "First in,First out"
158 *
159 * @ingroup kernel_queue_tests
160 *
161 * @see k_queue_init(), k_queue_alloc_append()
162 */
test_queue_alloc_append_user(void)163 void test_queue_alloc_append_user(void)
164 {
165 struct k_queue *q;
166
167 q = k_object_alloc(K_OBJ_QUEUE);
168 zassert_not_null(q, "no memory for allocated queue object");
169 k_queue_init(q);
170
171 for (int i = 0; i < LIST_LEN * 2; i++) {
172 qdata[i].data = i;
173 zassert_false(k_queue_alloc_append(q, &qdata[i]), NULL);
174 }
175
176 for (int i = 0; i < LIST_LEN * 2; i++) {
177 struct qdata *qd;
178
179 qd = k_queue_get(q, K_NO_WAIT);
180 zassert_true(qd != NULL, NULL);
181 zassert_equal(qd->data, i, NULL);
182 }
183 }
184
185 /**
186 * @brief Test to verify free of allocated elements of queue
187 * @ingroup kernel_queue_tests
188 */
test_auto_free(void)189 void test_auto_free(void)
190 {
191 /* Ensure any resources requested by the previous test were released
192 * by allocating the entire pool. It would have allocated two kernel
193 * objects and five queue elements. The queue elements should be
194 * auto-freed when they are de-queued, and the objects when all
195 * threads with permissions exit.
196 */
197
198 void *b[4];
199 int i;
200
201 for (i = 0; i < 4; i++) {
202 b[i] = k_heap_alloc(&test_pool, 64, K_FOREVER);
203 zassert_true(b[i] != NULL, "memory not auto released!");
204 }
205 }
206
207 #endif /* CONFIG_USERSPACE */
208