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_STACK_SIZE)
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));
34 	qd = k_queue_peek_head(q);
35 	zassert_equal(qd->data, 0);
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);
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));
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  */
ZTEST(queue_api_1cpu,test_queue_supv_to_user)73 ZTEST(queue_api_1cpu, test_queue_supv_to_user)
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 	if (!(IS_ENABLED(CONFIG_USERSPACE))) {
83 		ztest_test_skip();
84 	}
85 
86 	q = k_object_alloc(K_OBJ_QUEUE);
87 	zassert_not_null(q, "no memory for allocated queue object");
88 	k_queue_init(q);
89 
90 	sem = k_object_alloc(K_OBJ_SEM);
91 	zassert_not_null(sem, "no memory for semaphore object");
92 	k_sem_init(sem, 0, 1);
93 
94 	for (int i = 0; i < (LIST_LEN * 2); i = i + 2) {
95 		/* Just for test purposes -- not safe to do this in the
96 		 * real world as user mode shouldn't have any access to the
97 		 * snode struct
98 		 */
99 		qdata[i].data = i;
100 		qdata[i].allocated = false;
101 		qdata[i].snode.next = NULL;
102 		k_queue_append(q, &qdata[i]);
103 
104 		qdata[i + 1].data = i + 1;
105 		qdata[i + 1].allocated = true;
106 		qdata[i + 1].snode.next = NULL;
107 		zassert_false(k_queue_alloc_append(q, &qdata[i + 1]));
108 	}
109 
110 	k_thread_create(&child_thread, child_stack, STACK_SIZE,
111 			child_thread_get, q, sem, NULL, K_HIGHEST_THREAD_PRIO,
112 			K_USER | K_INHERIT_PERMS, K_NO_WAIT);
113 
114 	k_yield();
115 
116 	/* child thread runs until blocking on the last k_queue_get() call */
117 	k_queue_cancel_wait(q);
118 	k_sem_take(sem, K_FOREVER);
119 }
120 
121 /**
122  * @brief verify allocate and feature "Last In, First Out"
123  *
124  * @details Create a new queue
125  * And allocated memory for the queue
126  * Initialize and insert data item in sequence.
127  * Verify the feather "Last in,First out"
128  *
129  * @ingroup kernel_queue_tests
130  *
131  * @see k_queue_alloc_prepend()
132  */
ZTEST_USER(queue_api,test_queue_alloc_prepend_user)133 ZTEST_USER(queue_api, test_queue_alloc_prepend_user)
134 {
135 	struct k_queue *q;
136 
137 	q = k_object_alloc(K_OBJ_QUEUE);
138 	zassert_not_null(q, "no memory for allocated queue object");
139 	k_queue_init(q);
140 
141 	for (int i = 0; i < LIST_LEN * 2; i++) {
142 		qdata[i].data = i;
143 		zassert_false(k_queue_alloc_prepend(q, &qdata[i]));
144 	}
145 
146 	for (int i = (LIST_LEN * 2) - 1; i >= 0; i--) {
147 		struct qdata *qd;
148 
149 		qd = k_queue_get(q, K_NO_WAIT);
150 		zassert_true(qd != NULL);
151 		zassert_equal(qd->data, i);
152 	}
153 }
154 
155 /**
156  * @brief verify feature of queue "First In, First Out"
157  *
158  * @details Create a new queue
159  * And allocated memory for the queue
160  * Initialize and insert data item in sequence.
161  * Verify the feather "First in,First out"
162  *
163  * @ingroup kernel_queue_tests
164  *
165  * @see k_queue_init(), k_queue_alloc_append()
166  */
ZTEST_USER(queue_api,test_queue_alloc_append_user)167 ZTEST_USER(queue_api, test_queue_alloc_append_user)
168 {
169 	struct k_queue *q;
170 
171 	q = k_object_alloc(K_OBJ_QUEUE);
172 	zassert_not_null(q, "no memory for allocated queue object");
173 	k_queue_init(q);
174 
175 	for (int i = 0; i < LIST_LEN * 2; i++) {
176 		qdata[i].data = i;
177 		zassert_false(k_queue_alloc_append(q, &qdata[i]));
178 	}
179 
180 	for (int i = 0; i < LIST_LEN * 2; i++) {
181 		struct qdata *qd;
182 
183 		qd = k_queue_get(q, K_NO_WAIT);
184 		zassert_true(qd != NULL);
185 		zassert_equal(qd->data, i);
186 	}
187 }
188 
189 /**
190  * @brief Test to verify free of allocated elements of queue
191  * @ingroup kernel_queue_tests
192  */
ZTEST(queue_api,test_auto_free)193 ZTEST(queue_api, test_auto_free)
194 {
195 	/* Ensure any resources requested by the previous test were released
196 	 * by allocating the entire pool. It would have allocated two kernel
197 	 * objects and five queue elements. The queue elements should be
198 	 * auto-freed when they are de-queued, and the objects when all
199 	 * threads with permissions exit.
200 	 */
201 	void *b[4];
202 	int i;
203 
204 	if (!(IS_ENABLED(CONFIG_USERSPACE))) {
205 		ztest_test_skip();
206 	}
207 
208 	for (i = 0; i < 4; i++) {
209 		b[i] = k_heap_alloc(&test_pool, 64, K_FOREVER);
210 		zassert_true(b[i] != NULL, "memory not auto released!");
211 	}
212 
213 	for (i = 0; i < 4; i++) {
214 		k_heap_free(&test_pool, b[i]);
215 	}
216 }
217 
218 #endif /* CONFIG_USERSPACE */
219