blob: b20ab0c3f658107a2225b93c18835fa28d178791 [file] [log] [blame]
Benjamin Walsh456c6da2016-09-02 18:55:39 -04001/*
2 * Copyright (c) 2016 Wind River Systems, Inc.
3 *
David B. Kinderac74d8b2017-01-18 17:01:01 -08004 * SPDX-License-Identifier: Apache-2.0
Benjamin Walsh456c6da2016-09-02 18:55:39 -04005 */
6
7/**
8 * @file
9 * @brief Message queues.
10 */
11
12
13#include <kernel.h>
Benjamin Walshf6ca7de2016-11-08 10:36:50 -050014#include <kernel_structs.h>
Anas Nashif569f0b42016-12-17 13:18:45 -050015#include <debug/object_tracing_common.h>
Benjamin Walsh456c6da2016-09-02 18:55:39 -040016#include <toolchain.h>
Anas Nashif397d29d2017-06-17 11:30:47 -040017#include <linker/sections.h>
Benjamin Walsh456c6da2016-09-02 18:55:39 -040018#include <string.h>
19#include <wait_q.h>
20#include <misc/dlist.h>
Allan Stephense7d2cc22016-10-19 16:10:46 -050021#include <init.h>
Andrew Boie82edb6e2017-10-02 10:53:06 -070022#include <syscall_handler.h>
Allan Stephense7d2cc22016-10-19 16:10:46 -050023
24extern struct k_msgq _k_msgq_list_start[];
25extern struct k_msgq _k_msgq_list_end[];
26
Anas Nashif2f203c22016-12-18 06:57:45 -050027#ifdef CONFIG_OBJECT_TRACING
Allan Stephense7d2cc22016-10-19 16:10:46 -050028
Maciek Borzecki059544d2017-05-18 12:16:45 +020029struct k_msgq *_trace_list_k_msgq;
30
Allan Stephense7d2cc22016-10-19 16:10:46 -050031/*
32 * Complete initialization of statically defined message queues.
33 */
34static int init_msgq_module(struct device *dev)
35{
36 ARG_UNUSED(dev);
37
38 struct k_msgq *msgq;
39
40 for (msgq = _k_msgq_list_start; msgq < _k_msgq_list_end; msgq++) {
41 SYS_TRACING_OBJ_INIT(k_msgq, msgq);
42 }
43 return 0;
44}
45
Andrew Boie0b474ee2016-11-08 11:06:55 -080046SYS_INIT(init_msgq_module, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_OBJECTS);
Allan Stephense7d2cc22016-10-19 16:10:46 -050047
Anas Nashif2f203c22016-12-18 06:57:45 -050048#endif /* CONFIG_OBJECT_TRACING */
Benjamin Walsh456c6da2016-09-02 18:55:39 -040049
Andrew Boie0fe789f2018-04-12 18:35:56 -070050void k_msgq_init(struct k_msgq *q, char *buffer, size_t msg_size,
51 u32_t max_msgs)
Benjamin Walsh456c6da2016-09-02 18:55:39 -040052{
53 q->msg_size = msg_size;
54 q->max_msgs = max_msgs;
55 q->buffer_start = buffer;
56 q->buffer_end = buffer + (max_msgs * msg_size);
57 q->read_ptr = buffer;
58 q->write_ptr = buffer;
59 q->used_msgs = 0;
Andrew Boie0fe789f2018-04-12 18:35:56 -070060 q->flags = 0;
Andy Rossccf3bf72018-05-10 11:10:34 -070061 _waitq_init(&q->wait_q);
Allan Stephense7d2cc22016-10-19 16:10:46 -050062 SYS_TRACING_OBJ_INIT(k_msgq, q);
Andrew Boie945af952017-08-22 13:15:23 -070063
64 _k_object_init(q);
Benjamin Walsh456c6da2016-09-02 18:55:39 -040065}
66
Andrew Boie0fe789f2018-04-12 18:35:56 -070067int _impl_k_msgq_alloc_init(struct k_msgq *q, size_t msg_size,
68 u32_t max_msgs)
Andrew Boie82edb6e2017-10-02 10:53:06 -070069{
Andrew Boie0fe789f2018-04-12 18:35:56 -070070 void *buffer;
71 int ret;
72 size_t total_size;
Andrew Boie82edb6e2017-10-02 10:53:06 -070073
Kumar Gala07763922018-07-25 12:38:05 -050074 if (__builtin_umul_overflow((unsigned int)msg_size, max_msgs,
75 (unsigned int *)&total_size)) {
Andrew Boie0fe789f2018-04-12 18:35:56 -070076 ret = -EINVAL;
77 } else {
78 buffer = z_thread_malloc(total_size);
Flavio Ceolinea716bf2018-09-20 16:30:45 -070079 if (buffer != NULL) {
Andrew Boie0fe789f2018-04-12 18:35:56 -070080 k_msgq_init(q, buffer, msg_size, max_msgs);
81 q->flags = K_MSGQ_FLAG_ALLOC;
82 ret = 0;
83 } else {
84 ret = -ENOMEM;
85 }
86 }
87
88 return ret;
89}
90
91#ifdef CONFIG_USERSPACE
Andrew Boie8345e5e2018-05-04 15:57:57 -070092Z_SYSCALL_HANDLER(k_msgq_alloc_init, q, msg_size, max_msgs)
Andrew Boie0fe789f2018-04-12 18:35:56 -070093{
Andrew Boie8345e5e2018-05-04 15:57:57 -070094 Z_OOPS(Z_SYSCALL_OBJ_NEVER_INIT(q, K_OBJ_MSGQ));
Andrew Boie0fe789f2018-04-12 18:35:56 -070095
96 return _impl_k_msgq_alloc_init((struct k_msgq *)q, msg_size, max_msgs);
Andrew Boie82edb6e2017-10-02 10:53:06 -070097}
98#endif
99
Andrew Boie0fe789f2018-04-12 18:35:56 -0700100void k_msgq_cleanup(struct k_msgq *q)
101{
Andy Ross3ce9c842018-05-18 13:06:13 -0700102 __ASSERT_NO_MSG(!_waitq_head(&q->wait_q));
Andrew Boie0fe789f2018-04-12 18:35:56 -0700103
104 if (q->flags & K_MSGQ_FLAG_ALLOC) {
105 k_free(q->buffer_start);
106 q->flags &= ~K_MSGQ_FLAG_ALLOC;
107 }
108}
109
110
Andrew Boie82edb6e2017-10-02 10:53:06 -0700111int _impl_k_msgq_put(struct k_msgq *q, void *data, s32_t timeout)
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400112{
Benjamin Walsh8215ce12016-11-09 19:45:19 -0500113 __ASSERT(!_is_in_isr() || timeout == K_NO_WAIT, "");
114
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400115 unsigned int key = irq_lock();
Benjamin Walshb7ef0cb2016-10-05 17:32:01 -0400116 struct k_thread *pending_thread;
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400117 int result;
118
119 if (q->used_msgs < q->max_msgs) {
120 /* message queue isn't full */
121 pending_thread = _unpend_first_thread(&q->wait_q);
Flavio Ceolinea716bf2018-09-20 16:30:45 -0700122 if (pending_thread != NULL) {
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400123 /* give message to waiting thread */
Flavio Ceolin66994232018-08-13 15:17:04 -0700124 (void)memcpy(pending_thread->base.swap_data, data,
Benjamin Walshf6ca7de2016-11-08 10:36:50 -0500125 q->msg_size);
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400126 /* wake up waiting thread */
127 _set_thread_return_value(pending_thread, 0);
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400128 _ready_thread(pending_thread);
Andy Ross15cb5d72018-04-02 18:40:10 -0700129 _reschedule(key);
Andy Ross8606fab2018-03-26 10:54:40 -0700130 return 0;
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400131 } else {
132 /* put message in queue */
Flavio Ceolin66994232018-08-13 15:17:04 -0700133 (void)memcpy(q->write_ptr, data, q->msg_size);
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400134 q->write_ptr += q->msg_size;
135 if (q->write_ptr == q->buffer_end) {
136 q->write_ptr = q->buffer_start;
137 }
138 q->used_msgs++;
139 }
140 result = 0;
141 } else if (timeout == K_NO_WAIT) {
142 /* don't wait for message space to become available */
143 result = -ENOMSG;
144 } else {
145 /* wait for put message success, failure, or timeout */
Benjamin Walshf6ca7de2016-11-08 10:36:50 -0500146 _current->base.swap_data = data;
Andy Rosse0a572b2018-03-26 11:58:10 -0700147 return _pend_current_thread(key, &q->wait_q, timeout);
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400148 }
149
150 irq_unlock(key);
151
152 return result;
153}
154
Andrew Boie82edb6e2017-10-02 10:53:06 -0700155#ifdef CONFIG_USERSPACE
Andrew Boie8345e5e2018-05-04 15:57:57 -0700156Z_SYSCALL_HANDLER(k_msgq_put, msgq_p, data, timeout)
Andrew Boie82edb6e2017-10-02 10:53:06 -0700157{
158 struct k_msgq *q = (struct k_msgq *)msgq_p;
Andrew Boie82edb6e2017-10-02 10:53:06 -0700159
Andrew Boie8345e5e2018-05-04 15:57:57 -0700160 Z_OOPS(Z_SYSCALL_OBJ(q, K_OBJ_MSGQ));
161 Z_OOPS(Z_SYSCALL_MEMORY_READ(data, q->msg_size));
Andrew Boie82edb6e2017-10-02 10:53:06 -0700162
163 return _impl_k_msgq_put(q, (void *)data, timeout);
164}
165#endif
166
Youvedeep Singh188c1ab2018-03-19 20:02:40 +0530167void _impl_k_msgq_get_attrs(struct k_msgq *q, struct k_msgq_attrs *attrs)
168{
169 attrs->msg_size = q->msg_size;
170 attrs->max_msgs = q->max_msgs;
171 attrs->used_msgs = q->used_msgs;
172}
173
174#ifdef CONFIG_USERSPACE
Andrew Boie8345e5e2018-05-04 15:57:57 -0700175Z_SYSCALL_HANDLER(k_msgq_get_attrs, msgq_p, attrs)
Youvedeep Singh188c1ab2018-03-19 20:02:40 +0530176{
177 struct k_msgq *q = (struct k_msgq *)msgq_p;
178
Andrew Boie8345e5e2018-05-04 15:57:57 -0700179 Z_OOPS(Z_SYSCALL_OBJ(q, K_OBJ_MSGQ));
180 Z_OOPS(Z_SYSCALL_MEMORY_WRITE(attrs, sizeof(struct k_msgq_attrs)));
Youvedeep Singh188c1ab2018-03-19 20:02:40 +0530181 _impl_k_msgq_get_attrs(q, (struct k_msgq_attrs *) attrs);
182 return 0;
183}
184#endif
185
Andrew Boie82edb6e2017-10-02 10:53:06 -0700186int _impl_k_msgq_get(struct k_msgq *q, void *data, s32_t timeout)
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400187{
Benjamin Walsh8215ce12016-11-09 19:45:19 -0500188 __ASSERT(!_is_in_isr() || timeout == K_NO_WAIT, "");
189
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400190 unsigned int key = irq_lock();
Benjamin Walshb7ef0cb2016-10-05 17:32:01 -0400191 struct k_thread *pending_thread;
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400192 int result;
193
194 if (q->used_msgs > 0) {
195 /* take first available message from queue */
Flavio Ceolin66994232018-08-13 15:17:04 -0700196 (void)memcpy(data, q->read_ptr, q->msg_size);
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400197 q->read_ptr += q->msg_size;
198 if (q->read_ptr == q->buffer_end) {
199 q->read_ptr = q->buffer_start;
200 }
201 q->used_msgs--;
202
203 /* handle first thread waiting to write (if any) */
204 pending_thread = _unpend_first_thread(&q->wait_q);
Flavio Ceolin4218d5f2018-09-17 09:39:51 -0700205 if (pending_thread != NULL) {
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400206 /* add thread's message to queue */
Flavio Ceolin66994232018-08-13 15:17:04 -0700207 (void)memcpy(q->write_ptr, pending_thread->base.swap_data,
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400208 q->msg_size);
209 q->write_ptr += q->msg_size;
210 if (q->write_ptr == q->buffer_end) {
211 q->write_ptr = q->buffer_start;
212 }
213 q->used_msgs++;
214
215 /* wake up waiting thread */
216 _set_thread_return_value(pending_thread, 0);
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400217 _ready_thread(pending_thread);
Andy Ross15cb5d72018-04-02 18:40:10 -0700218 _reschedule(key);
Andy Ross8606fab2018-03-26 10:54:40 -0700219 return 0;
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400220 }
221 result = 0;
222 } else if (timeout == K_NO_WAIT) {
223 /* don't wait for a message to become available */
224 result = -ENOMSG;
225 } else {
226 /* wait for get message success or timeout */
Benjamin Walshf6ca7de2016-11-08 10:36:50 -0500227 _current->base.swap_data = data;
Andy Rosse0a572b2018-03-26 11:58:10 -0700228 return _pend_current_thread(key, &q->wait_q, timeout);
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400229 }
230
231 irq_unlock(key);
232
233 return result;
234}
235
Andrew Boie82edb6e2017-10-02 10:53:06 -0700236#ifdef CONFIG_USERSPACE
Andrew Boie8345e5e2018-05-04 15:57:57 -0700237Z_SYSCALL_HANDLER(k_msgq_get, msgq_p, data, timeout)
Andrew Boie82edb6e2017-10-02 10:53:06 -0700238{
239 struct k_msgq *q = (struct k_msgq *)msgq_p;
Andrew Boie82edb6e2017-10-02 10:53:06 -0700240
Andrew Boie8345e5e2018-05-04 15:57:57 -0700241 Z_OOPS(Z_SYSCALL_OBJ(q, K_OBJ_MSGQ));
242 Z_OOPS(Z_SYSCALL_MEMORY_WRITE(data, q->msg_size));
Andrew Boie82edb6e2017-10-02 10:53:06 -0700243
244 return _impl_k_msgq_get(q, (void *)data, timeout);
245}
246#endif
247
Sathish Kuttana8aa2352018-11-09 21:04:36 -0800248int _impl_k_msgq_peek(struct k_msgq *q, void *data)
249{
250 unsigned int key = irq_lock();
251 int result;
252
253 if (q->used_msgs > 0) {
254 /* take first available message from queue */
255 (void)memcpy(data, q->read_ptr, q->msg_size);
256 result = 0;
257 } else {
258 /* don't wait for a message to become available */
259 result = -ENOMSG;
260 }
261
262 irq_unlock(key);
263
264 return result;
265}
266
267#ifdef CONFIG_USERSPACE
268Z_SYSCALL_HANDLER(k_msgq_peek, msgq_p, data)
269{
270 struct k_msgq *q = (struct k_msgq *)msgq_p;
271
272 Z_OOPS(Z_SYSCALL_OBJ(q, K_OBJ_MSGQ));
273 Z_OOPS(Z_SYSCALL_MEMORY_WRITE(data, q->msg_size));
274
275 return _impl_k_msgq_peek(q, (void *)data);
276}
277#endif
278
Andrew Boie82edb6e2017-10-02 10:53:06 -0700279void _impl_k_msgq_purge(struct k_msgq *q)
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400280{
281 unsigned int key = irq_lock();
Benjamin Walshb7ef0cb2016-10-05 17:32:01 -0400282 struct k_thread *pending_thread;
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400283
Peter Mitsis340d00a2016-09-22 13:59:00 -0400284 /* wake up any threads that are waiting to write */
285 while ((pending_thread = _unpend_first_thread(&q->wait_q)) != NULL) {
286 _set_thread_return_value(pending_thread, -ENOMSG);
Peter Mitsis340d00a2016-09-22 13:59:00 -0400287 _ready_thread(pending_thread);
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400288 }
289
Peter Mitsis340d00a2016-09-22 13:59:00 -0400290 q->used_msgs = 0;
291 q->read_ptr = q->write_ptr;
292
Andy Ross15cb5d72018-04-02 18:40:10 -0700293 _reschedule(key);
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400294}
Andrew Boie82edb6e2017-10-02 10:53:06 -0700295
296#ifdef CONFIG_USERSPACE
Andrew Boie8345e5e2018-05-04 15:57:57 -0700297Z_SYSCALL_HANDLER1_SIMPLE_VOID(k_msgq_purge, K_OBJ_MSGQ, struct k_msgq *);
298Z_SYSCALL_HANDLER1_SIMPLE(k_msgq_num_free_get, K_OBJ_MSGQ, struct k_msgq *);
299Z_SYSCALL_HANDLER1_SIMPLE(k_msgq_num_used_get, K_OBJ_MSGQ, struct k_msgq *);
Andrew Boie225e4c02017-10-12 09:54:26 -0700300#endif