blob: 84a21deb5ba982ef9f006fbc1348e7ba64b158d0 [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>
Stephanos Ioannidis2d746042019-10-25 00:08:21 +090019#include <ksched.h>
Benjamin Walsh456c6da2016-09-02 18:55:39 -040020#include <wait_q.h>
Anas Nashifee9dd1a2019-06-26 10:33:41 -040021#include <sys/dlist.h>
Anas Nashif6ecadb02019-06-26 10:33:45 -040022#include <sys/math_extras.h>
Allan Stephense7d2cc22016-10-19 16:10:46 -050023#include <init.h>
Andrew Boie82edb6e2017-10-02 10:53:06 -070024#include <syscall_handler.h>
Andy Ross4f911e12018-09-05 10:13:38 -070025#include <kernel_internal.h>
Allan Stephense7d2cc22016-10-19 16:10:46 -050026
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
Nicolas Pitreaa9228852019-06-03 13:01:43 -040038 Z_STRUCT_SECTION_FOREACH(k_msgq, msgq) {
Allan Stephense7d2cc22016-10-19 16:10:46 -050039 SYS_TRACING_OBJ_INIT(k_msgq, msgq);
40 }
41 return 0;
42}
43
Andrew Boie0b474ee2016-11-08 11:06:55 -080044SYS_INIT(init_msgq_module, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_OBJECTS);
Allan Stephense7d2cc22016-10-19 16:10:46 -050045
Anas Nashif2f203c22016-12-18 06:57:45 -050046#endif /* CONFIG_OBJECT_TRACING */
Benjamin Walsh456c6da2016-09-02 18:55:39 -040047
Anas Nashif7bde81f2019-06-19 07:30:50 -040048void k_msgq_init(struct k_msgq *msgq, char *buffer, size_t msg_size,
Andrew Boie0fe789f2018-04-12 18:35:56 -070049 u32_t max_msgs)
Benjamin Walsh456c6da2016-09-02 18:55:39 -040050{
Anas Nashif7bde81f2019-06-19 07:30:50 -040051 msgq->msg_size = msg_size;
52 msgq->max_msgs = max_msgs;
53 msgq->buffer_start = buffer;
54 msgq->buffer_end = buffer + (max_msgs * msg_size);
55 msgq->read_ptr = buffer;
56 msgq->write_ptr = buffer;
57 msgq->used_msgs = 0;
58 msgq->flags = 0;
59 z_waitq_init(&msgq->wait_q);
60 msgq->lock = (struct k_spinlock) {};
Andrew Boie945af952017-08-22 13:15:23 -070061
Anas Nashif7bde81f2019-06-19 07:30:50 -040062 SYS_TRACING_OBJ_INIT(k_msgq, msgq);
63
64 z_object_init(msgq);
Benjamin Walsh456c6da2016-09-02 18:55:39 -040065}
66
Anas Nashif7bde81f2019-06-19 07:30:50 -040067int z_impl_k_msgq_alloc_init(struct k_msgq *msgq, size_t msg_size,
Andrew Boie0fe789f2018-04-12 18:35:56 -070068 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
Jakob Olesenc8708d92019-05-07 10:17:35 -070074 if (size_mul_overflow(msg_size, max_msgs, &total_size)) {
Andrew Boie0fe789f2018-04-12 18:35:56 -070075 ret = -EINVAL;
76 } else {
77 buffer = z_thread_malloc(total_size);
Flavio Ceolinea716bf2018-09-20 16:30:45 -070078 if (buffer != NULL) {
Anas Nashif7bde81f2019-06-19 07:30:50 -040079 k_msgq_init(msgq, buffer, msg_size, max_msgs);
80 msgq->flags = K_MSGQ_FLAG_ALLOC;
Andrew Boie0fe789f2018-04-12 18:35:56 -070081 ret = 0;
82 } else {
83 ret = -ENOMEM;
84 }
85 }
86
87 return ret;
88}
89
90#ifdef CONFIG_USERSPACE
Andy Ross65649742019-08-06 13:34:31 -070091int z_vrfy_k_msgq_alloc_init(struct k_msgq *q, size_t msg_size,
92 u32_t 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
Andy Ross65649742019-08-06 13:34:31 -070096 return z_impl_k_msgq_alloc_init(q, msg_size, max_msgs);
Andrew Boie82edb6e2017-10-02 10:53:06 -070097}
Andy Ross65649742019-08-06 13:34:31 -070098#include <syscalls/k_msgq_alloc_init_mrsh.c>
Andrew Boie82edb6e2017-10-02 10:53:06 -070099#endif
100
Anas Nashif7bde81f2019-06-19 07:30:50 -0400101void k_msgq_cleanup(struct k_msgq *msgq)
Andrew Boie0fe789f2018-04-12 18:35:56 -0700102{
Anas Nashif7bde81f2019-06-19 07:30:50 -0400103 __ASSERT_NO_MSG(z_waitq_head(&msgq->wait_q) == NULL);
Andrew Boie0fe789f2018-04-12 18:35:56 -0700104
Anas Nashif7bde81f2019-06-19 07:30:50 -0400105 if ((msgq->flags & K_MSGQ_FLAG_ALLOC) != 0) {
106 k_free(msgq->buffer_start);
107 msgq->flags &= ~K_MSGQ_FLAG_ALLOC;
Andrew Boie0fe789f2018-04-12 18:35:56 -0700108 }
109}
110
111
Anas Nashif7bde81f2019-06-19 07:30:50 -0400112int z_impl_k_msgq_put(struct k_msgq *msgq, void *data, s32_t timeout)
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400113{
Andrew Boie4f77c2a2019-11-07 12:43:29 -0800114 __ASSERT(!arch_is_in_isr() || timeout == K_NO_WAIT, "");
Benjamin Walsh8215ce12016-11-09 19:45:19 -0500115
Benjamin Walshb7ef0cb2016-10-05 17:32:01 -0400116 struct k_thread *pending_thread;
Anas Nashif7bde81f2019-06-19 07:30:50 -0400117 k_spinlock_key_t key;
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400118 int result;
119
Anas Nashif7bde81f2019-06-19 07:30:50 -0400120 key = k_spin_lock(&msgq->lock);
121
122 if (msgq->used_msgs < msgq->max_msgs) {
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400123 /* message queue isn't full */
Anas Nashif7bde81f2019-06-19 07:30:50 -0400124 pending_thread = z_unpend_first_thread(&msgq->wait_q);
Flavio Ceolinea716bf2018-09-20 16:30:45 -0700125 if (pending_thread != NULL) {
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400126 /* give message to waiting thread */
Flavio Ceolin66994232018-08-13 15:17:04 -0700127 (void)memcpy(pending_thread->base.swap_data, data,
Anas Nashif7bde81f2019-06-19 07:30:50 -0400128 msgq->msg_size);
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400129 /* wake up waiting thread */
Andrew Boie4f77c2a2019-11-07 12:43:29 -0800130 arch_thread_return_value_set(pending_thread, 0);
Patrik Flykt4344e272019-03-08 14:19:05 -0700131 z_ready_thread(pending_thread);
Anas Nashif7bde81f2019-06-19 07:30:50 -0400132 z_reschedule(&msgq->lock, key);
Andy Ross8606fab2018-03-26 10:54:40 -0700133 return 0;
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400134 } else {
135 /* put message in queue */
Anas Nashif7bde81f2019-06-19 07:30:50 -0400136 (void)memcpy(msgq->write_ptr, data, msgq->msg_size);
137 msgq->write_ptr += msgq->msg_size;
138 if (msgq->write_ptr == msgq->buffer_end) {
139 msgq->write_ptr = msgq->buffer_start;
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400140 }
Anas Nashif7bde81f2019-06-19 07:30:50 -0400141 msgq->used_msgs++;
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400142 }
143 result = 0;
144 } else if (timeout == K_NO_WAIT) {
145 /* don't wait for message space to become available */
146 result = -ENOMSG;
147 } else {
148 /* wait for put message success, failure, or timeout */
Benjamin Walshf6ca7de2016-11-08 10:36:50 -0500149 _current->base.swap_data = data;
Anas Nashif7bde81f2019-06-19 07:30:50 -0400150 return z_pend_curr(&msgq->lock, key, &msgq->wait_q, timeout);
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400151 }
152
Anas Nashif7bde81f2019-06-19 07:30:50 -0400153 k_spin_unlock(&msgq->lock, key);
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400154
155 return result;
156}
157
Andrew Boie82edb6e2017-10-02 10:53:06 -0700158#ifdef CONFIG_USERSPACE
Andy Ross65649742019-08-06 13:34:31 -0700159static inline int z_vrfy_k_msgq_put(struct k_msgq *q, void *data, s32_t timeout)
Andrew Boie82edb6e2017-10-02 10:53:06 -0700160{
Andrew Boie8345e5e2018-05-04 15:57:57 -0700161 Z_OOPS(Z_SYSCALL_OBJ(q, K_OBJ_MSGQ));
162 Z_OOPS(Z_SYSCALL_MEMORY_READ(data, q->msg_size));
Andrew Boie82edb6e2017-10-02 10:53:06 -0700163
Andy Ross65649742019-08-06 13:34:31 -0700164 return z_impl_k_msgq_put(q, data, timeout);
Andrew Boie82edb6e2017-10-02 10:53:06 -0700165}
Andy Ross65649742019-08-06 13:34:31 -0700166#include <syscalls/k_msgq_put_mrsh.c>
Andrew Boie82edb6e2017-10-02 10:53:06 -0700167#endif
168
Anas Nashif7bde81f2019-06-19 07:30:50 -0400169void z_impl_k_msgq_get_attrs(struct k_msgq *msgq, struct k_msgq_attrs *attrs)
Youvedeep Singh188c1ab2018-03-19 20:02:40 +0530170{
Anas Nashif7bde81f2019-06-19 07:30:50 -0400171 attrs->msg_size = msgq->msg_size;
172 attrs->max_msgs = msgq->max_msgs;
173 attrs->used_msgs = msgq->used_msgs;
Youvedeep Singh188c1ab2018-03-19 20:02:40 +0530174}
175
176#ifdef CONFIG_USERSPACE
Andy Ross643701a2019-08-13 12:58:38 -0700177static inline void z_vrfy_k_msgq_get_attrs(struct k_msgq *q,
178 struct k_msgq_attrs *attrs)
Youvedeep Singh188c1ab2018-03-19 20:02:40 +0530179{
Andrew Boie8345e5e2018-05-04 15:57:57 -0700180 Z_OOPS(Z_SYSCALL_OBJ(q, K_OBJ_MSGQ));
181 Z_OOPS(Z_SYSCALL_MEMORY_WRITE(attrs, sizeof(struct k_msgq_attrs)));
Andy Ross65649742019-08-06 13:34:31 -0700182 z_impl_k_msgq_get_attrs(q, attrs);
Youvedeep Singh188c1ab2018-03-19 20:02:40 +0530183}
Andy Ross65649742019-08-06 13:34:31 -0700184#include <syscalls/k_msgq_get_attrs_mrsh.c>
Youvedeep Singh188c1ab2018-03-19 20:02:40 +0530185#endif
186
Anas Nashif7bde81f2019-06-19 07:30:50 -0400187int z_impl_k_msgq_get(struct k_msgq *msgq, void *data, s32_t timeout)
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400188{
Andrew Boie4f77c2a2019-11-07 12:43:29 -0800189 __ASSERT(!arch_is_in_isr() || timeout == K_NO_WAIT, "");
Benjamin Walsh8215ce12016-11-09 19:45:19 -0500190
Anas Nashif7bde81f2019-06-19 07:30:50 -0400191 k_spinlock_key_t key;
Benjamin Walshb7ef0cb2016-10-05 17:32:01 -0400192 struct k_thread *pending_thread;
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400193 int result;
194
Anas Nashif7bde81f2019-06-19 07:30:50 -0400195 key = k_spin_lock(&msgq->lock);
196
197 if (msgq->used_msgs > 0) {
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400198 /* take first available message from queue */
Anas Nashif7bde81f2019-06-19 07:30:50 -0400199 (void)memcpy(data, msgq->read_ptr, msgq->msg_size);
200 msgq->read_ptr += msgq->msg_size;
201 if (msgq->read_ptr == msgq->buffer_end) {
202 msgq->read_ptr = msgq->buffer_start;
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400203 }
Anas Nashif7bde81f2019-06-19 07:30:50 -0400204 msgq->used_msgs--;
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400205
206 /* handle first thread waiting to write (if any) */
Anas Nashif7bde81f2019-06-19 07:30:50 -0400207 pending_thread = z_unpend_first_thread(&msgq->wait_q);
Flavio Ceolin4218d5f2018-09-17 09:39:51 -0700208 if (pending_thread != NULL) {
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400209 /* add thread's message to queue */
Anas Nashif7bde81f2019-06-19 07:30:50 -0400210 (void)memcpy(msgq->write_ptr, pending_thread->base.swap_data,
211 msgq->msg_size);
212 msgq->write_ptr += msgq->msg_size;
213 if (msgq->write_ptr == msgq->buffer_end) {
214 msgq->write_ptr = msgq->buffer_start;
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400215 }
Anas Nashif7bde81f2019-06-19 07:30:50 -0400216 msgq->used_msgs++;
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400217
218 /* wake up waiting thread */
Andrew Boie4f77c2a2019-11-07 12:43:29 -0800219 arch_thread_return_value_set(pending_thread, 0);
Patrik Flykt4344e272019-03-08 14:19:05 -0700220 z_ready_thread(pending_thread);
Anas Nashif7bde81f2019-06-19 07:30:50 -0400221 z_reschedule(&msgq->lock, key);
Andy Ross8606fab2018-03-26 10:54:40 -0700222 return 0;
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400223 }
224 result = 0;
225 } else if (timeout == K_NO_WAIT) {
226 /* don't wait for a message to become available */
227 result = -ENOMSG;
228 } else {
229 /* wait for get message success or timeout */
Benjamin Walshf6ca7de2016-11-08 10:36:50 -0500230 _current->base.swap_data = data;
Anas Nashif7bde81f2019-06-19 07:30:50 -0400231 return z_pend_curr(&msgq->lock, key, &msgq->wait_q, timeout);
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400232 }
233
Anas Nashif7bde81f2019-06-19 07:30:50 -0400234 k_spin_unlock(&msgq->lock, key);
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400235
236 return result;
237}
238
Andrew Boie82edb6e2017-10-02 10:53:06 -0700239#ifdef CONFIG_USERSPACE
Andy Ross65649742019-08-06 13:34:31 -0700240static inline int z_vrfy_k_msgq_get(struct k_msgq *q, void *data, s32_t timeout)
Andrew Boie82edb6e2017-10-02 10:53:06 -0700241{
Andrew Boie8345e5e2018-05-04 15:57:57 -0700242 Z_OOPS(Z_SYSCALL_OBJ(q, K_OBJ_MSGQ));
243 Z_OOPS(Z_SYSCALL_MEMORY_WRITE(data, q->msg_size));
Andrew Boie82edb6e2017-10-02 10:53:06 -0700244
Andy Ross65649742019-08-06 13:34:31 -0700245 return z_impl_k_msgq_get(q, data, timeout);
Andrew Boie82edb6e2017-10-02 10:53:06 -0700246}
Andy Ross65649742019-08-06 13:34:31 -0700247#include <syscalls/k_msgq_get_mrsh.c>
Andrew Boie82edb6e2017-10-02 10:53:06 -0700248#endif
249
Anas Nashif7bde81f2019-06-19 07:30:50 -0400250int z_impl_k_msgq_peek(struct k_msgq *msgq, void *data)
Sathish Kuttana8aa2352018-11-09 21:04:36 -0800251{
Anas Nashif7bde81f2019-06-19 07:30:50 -0400252 k_spinlock_key_t key;
Sathish Kuttana8aa2352018-11-09 21:04:36 -0800253 int result;
254
Anas Nashif7bde81f2019-06-19 07:30:50 -0400255 key = k_spin_lock(&msgq->lock);
256
257 if (msgq->used_msgs > 0) {
Sathish Kuttana8aa2352018-11-09 21:04:36 -0800258 /* take first available message from queue */
Anas Nashif7bde81f2019-06-19 07:30:50 -0400259 (void)memcpy(data, msgq->read_ptr, msgq->msg_size);
Sathish Kuttana8aa2352018-11-09 21:04:36 -0800260 result = 0;
261 } else {
262 /* don't wait for a message to become available */
263 result = -ENOMSG;
264 }
265
Anas Nashif7bde81f2019-06-19 07:30:50 -0400266 k_spin_unlock(&msgq->lock, key);
Sathish Kuttana8aa2352018-11-09 21:04:36 -0800267
268 return result;
269}
270
271#ifdef CONFIG_USERSPACE
Andy Ross65649742019-08-06 13:34:31 -0700272static inline int z_vrfy_k_msgq_peek(struct k_msgq *q, void *data)
Sathish Kuttana8aa2352018-11-09 21:04:36 -0800273{
Sathish Kuttana8aa2352018-11-09 21:04:36 -0800274 Z_OOPS(Z_SYSCALL_OBJ(q, K_OBJ_MSGQ));
275 Z_OOPS(Z_SYSCALL_MEMORY_WRITE(data, q->msg_size));
276
Andy Ross65649742019-08-06 13:34:31 -0700277 return z_impl_k_msgq_peek(q, data);
Sathish Kuttana8aa2352018-11-09 21:04:36 -0800278}
Andy Ross65649742019-08-06 13:34:31 -0700279#include <syscalls/k_msgq_peek_mrsh.c>
Sathish Kuttana8aa2352018-11-09 21:04:36 -0800280#endif
281
Anas Nashif7bde81f2019-06-19 07:30:50 -0400282void z_impl_k_msgq_purge(struct k_msgq *msgq)
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400283{
Anas Nashif7bde81f2019-06-19 07:30:50 -0400284 k_spinlock_key_t key;
Benjamin Walshb7ef0cb2016-10-05 17:32:01 -0400285 struct k_thread *pending_thread;
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400286
Anas Nashif7bde81f2019-06-19 07:30:50 -0400287 key = k_spin_lock(&msgq->lock);
288
Peter Mitsis340d00a2016-09-22 13:59:00 -0400289 /* wake up any threads that are waiting to write */
Anas Nashif7bde81f2019-06-19 07:30:50 -0400290 while ((pending_thread = z_unpend_first_thread(&msgq->wait_q)) != NULL) {
Andrew Boie4f77c2a2019-11-07 12:43:29 -0800291 arch_thread_return_value_set(pending_thread, -ENOMSG);
Patrik Flykt4344e272019-03-08 14:19:05 -0700292 z_ready_thread(pending_thread);
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400293 }
294
Anas Nashif7bde81f2019-06-19 07:30:50 -0400295 msgq->used_msgs = 0;
296 msgq->read_ptr = msgq->write_ptr;
Peter Mitsis340d00a2016-09-22 13:59:00 -0400297
Anas Nashif7bde81f2019-06-19 07:30:50 -0400298 z_reschedule(&msgq->lock, key);
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400299}
Andrew Boie82edb6e2017-10-02 10:53:06 -0700300
301#ifdef CONFIG_USERSPACE
Andy Ross65649742019-08-06 13:34:31 -0700302static inline void z_vrfy_k_msgq_purge(struct k_msgq *q)
303{
304 Z_OOPS(Z_SYSCALL_OBJ(q, K_OBJ_MSGQ));
305 z_impl_k_msgq_purge(q);
306}
307#include <syscalls/k_msgq_purge_mrsh.c>
308
309static inline u32_t z_vrfy_k_msgq_num_free_get(struct k_msgq *q)
310{
311 Z_OOPS(Z_SYSCALL_OBJ(q, K_OBJ_MSGQ));
312 return z_impl_k_msgq_num_free_get(q);
313}
314#include <syscalls/k_msgq_num_free_get_mrsh.c>
315
316static inline u32_t z_vrfy_k_msgq_num_used_get(struct k_msgq *q)
317{
318 Z_OOPS(Z_SYSCALL_OBJ(q, K_OBJ_MSGQ));
319 return z_impl_k_msgq_num_used_get(q);
320}
321#include <syscalls/k_msgq_num_used_get_mrsh.c>
322
Andrew Boie225e4c02017-10-12 09:54:26 -0700323#endif