Skip to content

Commit 0e1f080

Browse files
committed
kernel: Add queue functionality
Adds queue functionality, taken from zephyr kernel code Signed-off-by: Jamie McCrae <[email protected]>
1 parent 86f5927 commit 0e1f080

File tree

3 files changed

+318
-0
lines changed

3 files changed

+318
-0
lines changed

kernel/CMakeLists.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#
2+
# Copyright (c) 2024 Nordic Semiconductor ASA
3+
#
4+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
#
6+
7+
if(CONFIG_KERNEL_QUEUE)
8+
zephyr_sources(queue.c)
9+
endif()

kernel/Kconfig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#
2+
# Copyright (c) 2025 Nordic Semiconductor ASA
3+
#
4+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
#
6+
7+
config KERNEL_QUEUE
8+
bool "Queue"

kernel/queue.c

Lines changed: 301 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,301 @@
1+
/*
2+
* Copyright (c) 2010-2016 Wind River Systems, Inc.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
/**
8+
* @file
9+
*
10+
* @brief dynamic-size QUEUE object.
11+
*/
12+
13+
14+
#include <zephyr/kernel.h>
15+
#include <zephyr/kernel_structs.h>
16+
17+
#include <zephyr/toolchain.h>
18+
#include <wait_q.h>
19+
#include <ksched.h>
20+
#include <zephyr/init.h>
21+
#include <zephyr/internal/syscall_handler.h>
22+
#include <kernel_internal.h>
23+
#include <zephyr/sys/check.h>
24+
25+
struct alloc_node {
26+
sys_sfnode_t node;
27+
void *data;
28+
};
29+
30+
void *z_queue_node_peek(sys_sfnode_t *node, bool needs_free)
31+
{
32+
void *ret;
33+
34+
if ((node != NULL) && (sys_sfnode_flags_get(node) != (uint8_t)0)) {
35+
/* If the flag is set, then the enqueue operation for this item
36+
* did a behind-the scenes memory allocation of an alloc_node
37+
* struct, which is what got put in the queue. Free it and pass
38+
* back the data pointer.
39+
*/
40+
struct alloc_node *anode;
41+
42+
anode = CONTAINER_OF(node, struct alloc_node, node);
43+
ret = anode->data;
44+
if (needs_free) {
45+
k_free(anode);
46+
}
47+
} else {
48+
/* Data was directly placed in the queue, the first word
49+
* reserved for the linked list. User mode isn't allowed to
50+
* do this, although it can get data sent this way.
51+
*/
52+
ret = (void *)node;
53+
}
54+
55+
return ret;
56+
}
57+
58+
void z_impl_k_queue_init(struct k_queue *queue)
59+
{
60+
sys_sflist_init(&queue->data_q);
61+
z_waitq_init(&queue->wait_q);
62+
#if defined(CONFIG_POLL)
63+
sys_dlist_init(&queue->poll_events);
64+
#endif
65+
66+
SYS_PORT_TRACING_OBJ_INIT(k_queue, queue);
67+
68+
k_object_init(queue);
69+
}
70+
71+
static inline void handle_poll_events(struct k_queue *queue, uint32_t state)
72+
{
73+
#ifdef CONFIG_POLL
74+
z_handle_obj_poll_events(&queue->poll_events, state);
75+
#else
76+
ARG_UNUSED(queue);
77+
ARG_UNUSED(state);
78+
#endif /* CONFIG_POLL */
79+
}
80+
81+
static int32_t queue_insert(struct k_queue *queue, void *prev, void *data,
82+
bool alloc, bool is_append)
83+
{
84+
SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_queue, queue_insert, queue, alloc);
85+
86+
if (is_append) {
87+
prev = sys_sflist_peek_tail(&queue->data_q);
88+
}
89+
90+
/* Only need to actually allocate if no threads are pending */
91+
if (alloc) {
92+
struct alloc_node *anode;
93+
94+
anode = z_thread_malloc(sizeof(*anode));
95+
if (anode == NULL) {
96+
SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_queue, queue_insert, queue, alloc,
97+
-ENOMEM);
98+
99+
return -ENOMEM;
100+
}
101+
anode->data = data;
102+
sys_sfnode_init(&anode->node, 0x1);
103+
data = anode;
104+
} else {
105+
sys_sfnode_init(data, 0x0);
106+
}
107+
108+
SYS_PORT_TRACING_OBJ_FUNC_BLOCKING(k_queue, queue_insert, queue, alloc, K_FOREVER);
109+
110+
sys_sflist_insert(&queue->data_q, prev, data);
111+
handle_poll_events(queue, K_POLL_STATE_DATA_AVAILABLE);
112+
113+
SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_queue, queue_insert, queue, alloc, 0);
114+
115+
return 0;
116+
}
117+
118+
void k_queue_insert(struct k_queue *queue, void *prev, void *data)
119+
{
120+
SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_queue, insert, queue);
121+
122+
(void)queue_insert(queue, prev, data, false, false);
123+
124+
SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_queue, insert, queue);
125+
}
126+
127+
void k_queue_append(struct k_queue *queue, void *data)
128+
{
129+
SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_queue, append, queue);
130+
131+
(void)queue_insert(queue, NULL, data, false, true);
132+
133+
SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_queue, append, queue);
134+
}
135+
136+
void k_queue_prepend(struct k_queue *queue, void *data)
137+
{
138+
SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_queue, prepend, queue);
139+
140+
(void)queue_insert(queue, NULL, data, false, false);
141+
142+
SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_queue, prepend, queue);
143+
}
144+
145+
int32_t z_impl_k_queue_alloc_append(struct k_queue *queue, void *data)
146+
{
147+
SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_queue, alloc_append, queue);
148+
149+
int32_t ret = queue_insert(queue, NULL, data, true, true);
150+
151+
SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_queue, alloc_append, queue, ret);
152+
153+
return ret;
154+
}
155+
156+
int32_t z_impl_k_queue_alloc_prepend(struct k_queue *queue, void *data)
157+
{
158+
SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_queue, alloc_prepend, queue);
159+
160+
int32_t ret = queue_insert(queue, NULL, data, true, false);
161+
162+
SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_queue, alloc_prepend, queue, ret);
163+
164+
return ret;
165+
}
166+
167+
int k_queue_append_list(struct k_queue *queue, void *head, void *tail)
168+
{
169+
SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_queue, append_list, queue);
170+
171+
/* invalid head or tail of list */
172+
CHECKIF((head == NULL) || (tail == NULL)) {
173+
SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_queue, append_list, queue, -EINVAL);
174+
175+
return -EINVAL;
176+
}
177+
178+
if (head != NULL) {
179+
sys_sflist_append_list(&queue->data_q, head, tail);
180+
}
181+
182+
SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_queue, append_list, queue, 0);
183+
184+
handle_poll_events(queue, K_POLL_STATE_DATA_AVAILABLE);
185+
return 0;
186+
}
187+
188+
int k_queue_merge_slist(struct k_queue *queue, sys_slist_t *list)
189+
{
190+
int ret;
191+
192+
SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_queue, merge_slist, queue);
193+
194+
/* list must not be empty */
195+
CHECKIF(sys_slist_is_empty(list)) {
196+
SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_queue, merge_slist, queue, -EINVAL);
197+
198+
return -EINVAL;
199+
}
200+
201+
/*
202+
* note: this works as long as:
203+
* - the slist implementation keeps the next pointer as the first
204+
* field of the node object type
205+
* - list->tail->next = NULL.
206+
* - sflist implementation only differs from slist by stuffing
207+
* flag bytes in the lower order bits of the data pointer
208+
* - source list is really an slist and not an sflist with flags set
209+
*/
210+
ret = k_queue_append_list(queue, list->head, list->tail);
211+
CHECKIF(ret != 0) {
212+
SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_queue, merge_slist, queue, ret);
213+
214+
return ret;
215+
}
216+
sys_slist_init(list);
217+
218+
SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_queue, merge_slist, queue, 0);
219+
220+
return 0;
221+
}
222+
223+
void *z_impl_k_queue_get(struct k_queue *queue, k_timeout_t timeout)
224+
{
225+
void *data;
226+
227+
SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_queue, get, queue, timeout);
228+
229+
if (likely(!sys_sflist_is_empty(&queue->data_q))) {
230+
sys_sfnode_t *node;
231+
232+
node = sys_sflist_get_not_empty(&queue->data_q);
233+
data = z_queue_node_peek(node, true);
234+
235+
SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_queue, get, queue, timeout, data);
236+
237+
return data;
238+
}
239+
240+
SYS_PORT_TRACING_OBJ_FUNC_BLOCKING(k_queue, get, queue, timeout);
241+
242+
if (K_TIMEOUT_EQ(timeout, K_NO_WAIT)) {
243+
SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_queue, get, queue, timeout, NULL);
244+
245+
return NULL;
246+
}
247+
248+
SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_queue, get, queue, timeout,
249+
(ret != 0) ? NULL : _current->base.swap_data);
250+
return _current->base.swap_data;
251+
}
252+
253+
bool k_queue_remove(struct k_queue *queue, void *data)
254+
{
255+
SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_queue, remove, queue);
256+
257+
bool ret = sys_sflist_find_and_remove(&queue->data_q, (sys_sfnode_t *)data);
258+
259+
SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_queue, remove, queue, ret);
260+
261+
return ret;
262+
}
263+
264+
bool k_queue_unique_append(struct k_queue *queue, void *data)
265+
{
266+
SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_queue, unique_append, queue);
267+
268+
sys_sfnode_t *test;
269+
270+
SYS_SFLIST_FOR_EACH_NODE(&queue->data_q, test) {
271+
if (test == (sys_sfnode_t *) data) {
272+
SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_queue, unique_append, queue, false);
273+
274+
return false;
275+
}
276+
}
277+
278+
k_queue_append(queue, data);
279+
280+
SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_queue, unique_append, queue, true);
281+
282+
return true;
283+
}
284+
285+
void *z_impl_k_queue_peek_head(struct k_queue *queue)
286+
{
287+
void *ret = z_queue_node_peek(sys_sflist_peek_head(&queue->data_q), false);
288+
289+
SYS_PORT_TRACING_OBJ_FUNC(k_queue, peek_head, queue, ret);
290+
291+
return ret;
292+
}
293+
294+
void *z_impl_k_queue_peek_tail(struct k_queue *queue)
295+
{
296+
void *ret = z_queue_node_peek(sys_sflist_peek_tail(&queue->data_q), false);
297+
298+
SYS_PORT_TRACING_OBJ_FUNC(k_queue, peek_tail, queue, ret);
299+
300+
return ret;
301+
}

0 commit comments

Comments
 (0)