blob: c590d44955784f8f7ff42129ab115ad3dc14143b [file] [log] [blame]
Luiz Augusto von Dentza7ddb872017-02-21 14:50:42 +02001/*
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 <kernel.h>
15#include <kernel_structs.h>
16#include <debug/object_tracing_common.h>
17#include <toolchain.h>
Anas Nashif397d29d2017-06-17 11:30:47 -040018#include <linker/sections.h>
Luiz Augusto von Dentza7ddb872017-02-21 14:50:42 +020019#include <wait_q.h>
20#include <ksched.h>
21#include <misc/slist.h>
22#include <init.h>
23
24extern struct k_queue _k_queue_list_start[];
25extern struct k_queue _k_queue_list_end[];
26
Luiz Augusto von Dentza7ddb872017-02-21 14:50:42 +020027#ifdef CONFIG_OBJECT_TRACING
28
Maciek Borzecki059544d2017-05-18 12:16:45 +020029struct k_queue *_trace_list_k_queue;
30
Luiz Augusto von Dentza7ddb872017-02-21 14:50:42 +020031/*
32 * Complete initialization of statically defined queues.
33 */
34static int init_queue_module(struct device *dev)
35{
36 ARG_UNUSED(dev);
37
38 struct k_queue *queue;
39
40 for (queue = _k_queue_list_start; queue < _k_queue_list_end; queue++) {
41 SYS_TRACING_OBJ_INIT(k_queue, queue);
42 }
43 return 0;
44}
45
46SYS_INIT(init_queue_module, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_OBJECTS);
47
48#endif /* CONFIG_OBJECT_TRACING */
49
50void k_queue_init(struct k_queue *queue)
51{
52 sys_slist_init(&queue->data_q);
53 sys_dlist_init(&queue->wait_q);
Luiz Augusto von Dentz7d01c5e2017-08-21 10:49:29 +030054#if defined(CONFIG_POLL)
55 sys_dlist_init(&queue->poll_events);
56#endif
Luiz Augusto von Dentza7ddb872017-02-21 14:50:42 +020057
58 SYS_TRACING_OBJ_INIT(k_queue, queue);
59}
60
Luiz Augusto von Dentz84db6412017-07-13 12:43:59 +030061#if !defined(CONFIG_POLL)
Luiz Augusto von Dentza7ddb872017-02-21 14:50:42 +020062static void prepare_thread_to_run(struct k_thread *thread, void *data)
63{
64 _abort_thread_timeout(thread);
65 _ready_thread(thread);
66 _set_thread_return_value_with_data(thread, 0, data);
67}
Luiz Augusto von Dentz84db6412017-07-13 12:43:59 +030068#endif /* CONFIG_POLL */
Luiz Augusto von Dentza7ddb872017-02-21 14:50:42 +020069
70/* returns 1 if a reschedule must take place, 0 otherwise */
Luiz Augusto von Dentz7d01c5e2017-08-21 10:49:29 +030071static inline int handle_poll_events(struct k_queue *queue)
Luiz Augusto von Dentza7ddb872017-02-21 14:50:42 +020072{
73#ifdef CONFIG_POLL
Kumar Galacc334c72017-04-21 10:55:34 -050074 u32_t state = K_POLL_STATE_DATA_AVAILABLE;
Luiz Augusto von Dentza7ddb872017-02-21 14:50:42 +020075
Luiz Augusto von Dentz7d01c5e2017-08-21 10:49:29 +030076 return _handle_obj_poll_events(&queue->poll_events, state);
Luiz Augusto von Dentza7ddb872017-02-21 14:50:42 +020077#else
78 return 0;
79#endif
80}
81
Paul Sokolovsky3f507072017-04-25 17:54:31 +030082void k_queue_cancel_wait(struct k_queue *queue)
83{
Luiz Augusto von Dentz84db6412017-07-13 12:43:59 +030084 unsigned int key = irq_lock();
85#if !defined(CONFIG_POLL)
Paul Sokolovsky3f507072017-04-25 17:54:31 +030086 struct k_thread *first_pending_thread;
Paul Sokolovsky3f507072017-04-25 17:54:31 +030087
88 first_pending_thread = _unpend_first_thread(&queue->wait_q);
89
90 if (first_pending_thread) {
91 prepare_thread_to_run(first_pending_thread, NULL);
92 if (!_is_in_isr() && _must_switch_threads()) {
93 (void)_Swap(key);
94 return;
95 }
Paul Sokolovsky3f507072017-04-25 17:54:31 +030096 }
Luiz Augusto von Dentz84db6412017-07-13 12:43:59 +030097#else
Luiz Augusto von Dentz7d01c5e2017-08-21 10:49:29 +030098 if (handle_poll_events(queue)) {
Luiz Augusto von Dentz84db6412017-07-13 12:43:59 +030099 (void)_Swap(key);
100 return;
101 }
102#endif /* !CONFIG_POLL */
Paul Sokolovsky3f507072017-04-25 17:54:31 +0300103
104 irq_unlock(key);
105}
106
Luiz Augusto von Dentza7ddb872017-02-21 14:50:42 +0200107void k_queue_insert(struct k_queue *queue, void *prev, void *data)
108{
Luiz Augusto von Dentz84db6412017-07-13 12:43:59 +0300109 unsigned int key = irq_lock();
110#if !defined(CONFIG_POLL)
Luiz Augusto von Dentza7ddb872017-02-21 14:50:42 +0200111 struct k_thread *first_pending_thread;
Luiz Augusto von Dentza7ddb872017-02-21 14:50:42 +0200112
113 first_pending_thread = _unpend_first_thread(&queue->wait_q);
114
115 if (first_pending_thread) {
116 prepare_thread_to_run(first_pending_thread, data);
117 if (!_is_in_isr() && _must_switch_threads()) {
118 (void)_Swap(key);
119 return;
120 }
Luiz Augusto von Dentz84db6412017-07-13 12:43:59 +0300121 irq_unlock(key);
122 return;
Luiz Augusto von Dentza7ddb872017-02-21 14:50:42 +0200123 }
Luiz Augusto von Dentz84db6412017-07-13 12:43:59 +0300124#endif /* !CONFIG_POLL */
125
126 sys_slist_insert(&queue->data_q, prev, data);
127
128#if defined(CONFIG_POLL)
Luiz Augusto von Dentz7d01c5e2017-08-21 10:49:29 +0300129 if (handle_poll_events(queue)) {
Luiz Augusto von Dentz84db6412017-07-13 12:43:59 +0300130 (void)_Swap(key);
131 return;
132 }
133#endif /* CONFIG_POLL */
Luiz Augusto von Dentza7ddb872017-02-21 14:50:42 +0200134
135 irq_unlock(key);
136}
137
138void k_queue_append(struct k_queue *queue, void *data)
139{
140 return k_queue_insert(queue, queue->data_q.tail, data);
141}
142
143void k_queue_prepend(struct k_queue *queue, void *data)
144{
145 return k_queue_insert(queue, NULL, data);
146}
147
148void k_queue_append_list(struct k_queue *queue, void *head, void *tail)
149{
150 __ASSERT(head && tail, "invalid head or tail");
151
Luiz Augusto von Dentz84db6412017-07-13 12:43:59 +0300152 unsigned int key = irq_lock();
153#if !defined(CONFIG_POLL)
Luiz Augusto von Dentza7ddb872017-02-21 14:50:42 +0200154 struct k_thread *first_thread, *thread;
Luiz Augusto von Dentza7ddb872017-02-21 14:50:42 +0200155
156 first_thread = _peek_first_pending_thread(&queue->wait_q);
157 while (head && ((thread = _unpend_first_thread(&queue->wait_q)))) {
158 prepare_thread_to_run(thread, head);
159 head = *(void **)head;
160 }
161
162 if (head) {
163 sys_slist_append_list(&queue->data_q, head, tail);
164 }
165
166 if (first_thread) {
167 if (!_is_in_isr() && _must_switch_threads()) {
168 (void)_Swap(key);
169 return;
170 }
Luiz Augusto von Dentza7ddb872017-02-21 14:50:42 +0200171 }
Luiz Augusto von Dentz84db6412017-07-13 12:43:59 +0300172#else
173 sys_slist_append_list(&queue->data_q, head, tail);
Luiz Augusto von Dentz7d01c5e2017-08-21 10:49:29 +0300174 if (handle_poll_events(queue)) {
Luiz Augusto von Dentz84db6412017-07-13 12:43:59 +0300175 (void)_Swap(key);
176 return;
177 }
178#endif /* !CONFIG_POLL */
Luiz Augusto von Dentza7ddb872017-02-21 14:50:42 +0200179
180 irq_unlock(key);
181}
182
183void k_queue_merge_slist(struct k_queue *queue, sys_slist_t *list)
184{
185 __ASSERT(!sys_slist_is_empty(list), "list must not be empty");
186
187 /*
188 * note: this works as long as:
189 * - the slist implementation keeps the next pointer as the first
190 * field of the node object type
191 * - list->tail->next = NULL.
192 */
193 k_queue_append_list(queue, list->head, list->tail);
194 sys_slist_init(list);
195}
196
Luiz Augusto von Dentz84db6412017-07-13 12:43:59 +0300197#if defined(CONFIG_POLL)
198static void *k_queue_poll(struct k_queue *queue, s32_t timeout)
199{
200 struct k_poll_event event;
201 int err;
202
203 k_poll_event_init(&event, K_POLL_TYPE_FIFO_DATA_AVAILABLE,
204 K_POLL_MODE_NOTIFY_ONLY, queue);
205
206 event.state = K_POLL_STATE_NOT_READY;
207
208 err = k_poll(&event, 1, timeout);
Luiz Augusto von Dentz7d01c5e2017-08-21 10:49:29 +0300209 if (err) {
Luiz Augusto von Dentz84db6412017-07-13 12:43:59 +0300210 return NULL;
211 }
212
Luiz Augusto von Dentz84db6412017-07-13 12:43:59 +0300213 __ASSERT_NO_MSG(event.state == K_POLL_STATE_FIFO_DATA_AVAILABLE);
214
215 return sys_slist_get(&queue->data_q);
216}
217#endif /* CONFIG_POLL */
218
Kumar Galacc334c72017-04-21 10:55:34 -0500219void *k_queue_get(struct k_queue *queue, s32_t timeout)
Luiz Augusto von Dentza7ddb872017-02-21 14:50:42 +0200220{
221 unsigned int key;
222 void *data;
223
224 key = irq_lock();
225
226 if (likely(!sys_slist_is_empty(&queue->data_q))) {
227 data = sys_slist_get_not_empty(&queue->data_q);
228 irq_unlock(key);
229 return data;
230 }
231
232 if (timeout == K_NO_WAIT) {
233 irq_unlock(key);
234 return NULL;
235 }
236
Luiz Augusto von Dentz84db6412017-07-13 12:43:59 +0300237#if defined(CONFIG_POLL)
238 irq_unlock(key);
239
240 return k_queue_poll(queue, timeout);
241
242#else
Luiz Augusto von Dentza7ddb872017-02-21 14:50:42 +0200243 _pend_current_thread(&queue->wait_q, timeout);
244
245 return _Swap(key) ? NULL : _current->base.swap_data;
Luiz Augusto von Dentz84db6412017-07-13 12:43:59 +0300246#endif /* CONFIG_POLL */
Luiz Augusto von Dentza7ddb872017-02-21 14:50:42 +0200247}