ChibiOS 21.11.4
chmboxes.c
Go to the documentation of this file.
1/*
2 ChibiOS - Copyright (C) 2006,2007,2008,2009,2010,2011,2012,2013,2014,
3 2015,2016,2017,2018,2019,2020,2021 Giovanni Di Sirio.
4
5 This file is part of ChibiOS.
6
7 ChibiOS is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation version 3 of the License.
10
11 ChibiOS is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18*/
19
20/**
21 * @file oslib/src/chmboxes.c
22 * @brief Mailboxes code.
23 *
24 * @addtogroup oslib_mailboxes
25 * @details Asynchronous messages.
26 * <h2>Operation mode</h2>
27 * A mailbox is an asynchronous communication mechanism.<br>
28 * Operations defined for mailboxes:
29 * - <b>Post</b>: Posts a message on the mailbox in FIFO order.
30 * - <b>Post Ahead</b>: Posts a message on the mailbox with urgent
31 * priority.
32 * - <b>Fetch</b>: A message is fetched from the mailbox and removed
33 * from the queue.
34 * - <b>Reset</b>: The mailbox is emptied and all the stored messages
35 * are lost.
36 * .
37 * A message is a variable of type msg_t that is guaranteed to have
38 * the same size of and be compatible with (data) pointers (anyway an
39 * explicit cast is needed).
40 * If larger messages need to be exchanged then a pointer to a
41 * structure can be posted in the mailbox but the posting side has
42 * no predefined way to know when the message has been processed. A
43 * possible approach is to allocate memory (from a memory pool for
44 * example) from the posting side and free it on the fetching side.
45 * Another approach is to set a "done" flag into the structure pointed
46 * by the message.
47 * @pre In order to use the mailboxes APIs the @p CH_CFG_USE_MAILBOXES
48 * option must be enabled in @p chconf.h.
49 * @note Compatible with RT and NIL.
50 * @{
51 */
52
53#include "ch.h"
54
55#if (CH_CFG_USE_MAILBOXES == TRUE) || defined(__DOXYGEN__)
56
57/*===========================================================================*/
58/* Module exported variables. */
59/*===========================================================================*/
60
61/*===========================================================================*/
62/* Module local types. */
63/*===========================================================================*/
64
65/*===========================================================================*/
66/* Module local variables. */
67/*===========================================================================*/
68
69/*===========================================================================*/
70/* Module local functions. */
71/*===========================================================================*/
72
73/*===========================================================================*/
74/* Module exported functions. */
75/*===========================================================================*/
76
77/**
78 * @brief Initializes a @p mailbox_t object.
79 *
80 * @param[out] mbp the pointer to the @p mailbox_t structure to be
81 * initialized
82 * @param[in] buf pointer to the messages buffer as an array of @p msg_t
83 * @param[in] n number of elements in the buffer array
84 *
85 * @init
86 */
87void chMBObjectInit(mailbox_t *mbp, msg_t *buf, size_t n) {
88
89 chDbgCheck((mbp != NULL) && (buf != NULL) && (n > (size_t)0));
90
91 mbp->buffer = buf;
92 mbp->rdptr = buf;
93 mbp->wrptr = buf;
94 mbp->top = &buf[n];
95 mbp->cnt = (size_t)0;
96 mbp->reset = false;
99}
100
101/**
102 * @brief Resets a @p mailbox_t object.
103 * @details All the waiting threads are resumed with status @p MSG_RESET and
104 * the queued messages are lost.
105 * @post The mailbox is in reset state, all operations will fail and
106 * return @p MSG_RESET until the mailbox is enabled again using
107 * @p chMBResumeX().
108 *
109 * @param[in] mbp the pointer to an initialized @p mailbox_t object
110 *
111 * @api
112 */
114
115 chSysLock();
116 chMBResetI(mbp);
118 chSysUnlock();
119}
120
121/**
122 * @brief Resets a @p mailbox_t object.
123 * @details All the waiting threads are resumed with status @p MSG_RESET and
124 * the queued messages are lost.
125 * @post The mailbox is in reset state, all operations will fail and
126 * return @p MSG_RESET until the mailbox is enabled again using
127 * @p chMBResumeX().
128 *
129 * @param[in] mbp the pointer to an initialized @p mailbox_t object
130 *
131 * @api
132 */
134
136 chDbgCheck(mbp != NULL);
137
138 mbp->wrptr = mbp->buffer;
139 mbp->rdptr = mbp->buffer;
140 mbp->cnt = (size_t)0;
141 mbp->reset = true;
144}
145
146/**
147 * @brief Posts a message into a mailbox.
148 * @details The invoking thread waits until a empty slot in the mailbox becomes
149 * available or the specified time runs out.
150 *
151 * @param[in] mbp the pointer to an initialized @p mailbox_t object
152 * @param[in] msg the message to be posted on the mailbox
153 * @param[in] timeout the number of ticks before the operation timeouts,
154 * the following special values are allowed:
155 * - @a TIME_IMMEDIATE immediate timeout.
156 * - @a TIME_INFINITE no timeout.
157 * .
158 * @return The operation status.
159 * @retval MSG_OK if a message has been correctly posted.
160 * @retval MSG_RESET if the mailbox has been reset.
161 * @retval MSG_TIMEOUT if the operation has timed out.
162 *
163 * @api
164 */
166 msg_t rdymsg;
167
168 chSysLock();
169 rdymsg = chMBPostTimeoutS(mbp, msg, timeout);
170 chSysUnlock();
171
172 return rdymsg;
173}
174
175/**
176 * @brief Posts a message into a mailbox.
177 * @details The invoking thread waits until a empty slot in the mailbox becomes
178 * available or the specified time runs out.
179 *
180 * @param[in] mbp the pointer to an initialized @p mailbox_t object
181 * @param[in] msg the message to be posted on the mailbox
182 * @param[in] timeout the number of ticks before the operation timeouts,
183 * the following special values are allowed:
184 * - @a TIME_IMMEDIATE immediate timeout.
185 * - @a TIME_INFINITE no timeout.
186 * .
187 * @return The operation status.
188 * @retval MSG_OK if a message has been correctly posted.
189 * @retval MSG_RESET if the mailbox has been reset.
190 * @retval MSG_TIMEOUT if the operation has timed out.
191 *
192 * @sclass
193 */
195 msg_t rdymsg;
196
198 chDbgCheck(mbp != NULL);
199
200 do {
201 /* If the mailbox is in reset state then returns immediately.*/
202 if (mbp->reset) {
203 return MSG_RESET;
204 }
205
206 /* Is there a free message slot in queue? if so then post.*/
207 if (chMBGetFreeCountI(mbp) > (size_t)0) {
208 *mbp->wrptr++ = msg;
209 if (mbp->wrptr >= mbp->top) {
210 mbp->wrptr = mbp->buffer;
211 }
212 mbp->cnt++;
213
214 /* If there is a reader waiting then makes it ready.*/
217
218 return MSG_OK;
219 }
220
221 /* No space in the queue, waiting for a slot to become available.*/
222 rdymsg = chThdEnqueueTimeoutS(&mbp->qw, timeout);
223 } while (rdymsg == MSG_OK);
224
225 return rdymsg;
226}
227
228/**
229 * @brief Posts a message into a mailbox.
230 * @details This variant is non-blocking, the function returns a timeout
231 * condition if the queue is full.
232 *
233 * @param[in] mbp the pointer to an initialized @p mailbox_t object
234 * @param[in] msg the message to be posted on the mailbox
235 * @return The operation status.
236 * @retval MSG_OK if a message has been correctly posted.
237 * @retval MSG_RESET if the mailbox has been reset.
238 * @retval MSG_TIMEOUT if the mailbox is full and the message cannot be
239 * posted.
240 *
241 * @iclass
242 */
244
246 chDbgCheck(mbp != NULL);
247
248 /* If the mailbox is in reset state then returns immediately.*/
249 if (mbp->reset) {
250 return MSG_RESET;
251 }
252
253 /* Is there a free message slot in queue? if so then post.*/
254 if (chMBGetFreeCountI(mbp) > (size_t)0) {
255 *mbp->wrptr++ = msg;
256 if (mbp->wrptr >= mbp->top) {
257 mbp->wrptr = mbp->buffer;
258 }
259 mbp->cnt++;
260
261 /* If there is a reader waiting then makes it ready.*/
263
264 return MSG_OK;
265 }
266
267 /* No space, immediate timeout.*/
268 return MSG_TIMEOUT;
269}
270
271/**
272 * @brief Posts an high priority message into a mailbox.
273 * @details The invoking thread waits until a empty slot in the mailbox becomes
274 * available or the specified time runs out.
275 *
276 * @param[in] mbp the pointer to an initialized @p mailbox_t object
277 * @param[in] msg the message to be posted on the mailbox
278 * @param[in] timeout the number of ticks before the operation timeouts,
279 * the following special values are allowed:
280 * - @a TIME_IMMEDIATE immediate timeout.
281 * - @a TIME_INFINITE no timeout.
282 * .
283 * @return The operation status.
284 * @retval MSG_OK if a message has been correctly posted.
285 * @retval MSG_RESET if the mailbox has been reset.
286 * @retval MSG_TIMEOUT if the operation has timed out.
287 *
288 * @api
289 */
291 msg_t rdymsg;
292
293 chSysLock();
294 rdymsg = chMBPostAheadTimeoutS(mbp, msg, timeout);
295 chSysUnlock();
296
297 return rdymsg;
298}
299
300/**
301 * @brief Posts an high priority message into a mailbox.
302 * @details The invoking thread waits until a empty slot in the mailbox becomes
303 * available or the specified time runs out.
304 *
305 * @param[in] mbp the pointer to an initialized @p mailbox_t object
306 * @param[in] msg the message to be posted on the mailbox
307 * @param[in] timeout the number of ticks before the operation timeouts,
308 * the following special values are allowed:
309 * - @a TIME_IMMEDIATE immediate timeout.
310 * - @a TIME_INFINITE no timeout.
311 * .
312 * @return The operation status.
313 * @retval MSG_OK if a message has been correctly posted.
314 * @retval MSG_RESET if the mailbox has been reset.
315 * @retval MSG_TIMEOUT if the operation has timed out.
316 *
317 * @sclass
318 */
320 msg_t rdymsg;
321
323 chDbgCheck(mbp != NULL);
324
325 do {
326 /* If the mailbox is in reset state then returns immediately.*/
327 if (mbp->reset) {
328 return MSG_RESET;
329 }
330
331 /* Is there a free message slot in queue? if so then post.*/
332 if (chMBGetFreeCountI(mbp) > (size_t)0) {
333 if (--mbp->rdptr < mbp->buffer) {
334 mbp->rdptr = mbp->top - 1;
335 }
336 *mbp->rdptr = msg;
337 mbp->cnt++;
338
339 /* If there is a reader waiting then makes it ready.*/
342
343 return MSG_OK;
344 }
345
346 /* No space in the queue, waiting for a slot to become available.*/
347 rdymsg = chThdEnqueueTimeoutS(&mbp->qw, timeout);
348 } while (rdymsg == MSG_OK);
349
350 return rdymsg;
351}
352
353/**
354 * @brief Posts an high priority message into a mailbox.
355 * @details This variant is non-blocking, the function returns a timeout
356 * condition if the queue is full.
357 *
358 * @param[in] mbp the pointer to an initialized @p mailbox_t object
359 * @param[in] msg the message to be posted on the mailbox
360 * @return The operation status.
361 * @retval MSG_OK if a message has been correctly posted.
362 * @retval MSG_RESET if the mailbox has been reset.
363 * @retval MSG_TIMEOUT if the mailbox is full and the message cannot be
364 * posted.
365 *
366 * @iclass
367 */
369
371 chDbgCheck(mbp != NULL);
372
373 /* If the mailbox is in reset state then returns immediately.*/
374 if (mbp->reset) {
375 return MSG_RESET;
376 }
377
378 /* Is there a free message slot in queue? if so then post.*/
379 if (chMBGetFreeCountI(mbp) > (size_t)0) {
380 if (--mbp->rdptr < mbp->buffer) {
381 mbp->rdptr = mbp->top - 1;
382 }
383 *mbp->rdptr = msg;
384 mbp->cnt++;
385
386 /* If there is a reader waiting then makes it ready.*/
388
389 return MSG_OK;
390 }
391
392 /* No space, immediate timeout.*/
393 return MSG_TIMEOUT;
394}
395
396/**
397 * @brief Retrieves a message from a mailbox.
398 * @details The invoking thread waits until a message is posted in the mailbox
399 * or the specified time runs out.
400 *
401 * @param[in] mbp the pointer to an initialized @p mailbox_t object
402 * @param[out] msgp pointer to a message variable for the received message
403 * @param[in] timeout the number of ticks before the operation timeouts,
404 * the following special values are allowed:
405 * - @a TIME_IMMEDIATE immediate timeout.
406 * - @a TIME_INFINITE no timeout.
407 * .
408 * @return The operation status.
409 * @retval MSG_OK if a message has been correctly fetched.
410 * @retval MSG_RESET if the mailbox has been reset.
411 * @retval MSG_TIMEOUT if the operation has timed out.
412 *
413 * @api
414 */
416 msg_t rdymsg;
417
418 chSysLock();
419 rdymsg = chMBFetchTimeoutS(mbp, msgp, timeout);
420 chSysUnlock();
421
422 return rdymsg;
423}
424
425/**
426 * @brief Retrieves a message from a mailbox.
427 * @details The invoking thread waits until a message is posted in the mailbox
428 * or the specified time runs out.
429 *
430 * @param[in] mbp the pointer to an initialized @p mailbox_t object
431 * @param[out] msgp pointer to a message variable for the received message
432 * @param[in] timeout the number of ticks before the operation timeouts,
433 * the following special values are allowed:
434 * - @a TIME_IMMEDIATE immediate timeout.
435 * - @a TIME_INFINITE no timeout.
436 * .
437 * @return The operation status.
438 * @retval MSG_OK if a message has been correctly fetched.
439 * @retval MSG_RESET if the mailbox has been reset.
440 * @retval MSG_TIMEOUT if the operation has timed out.
441 *
442 * @sclass
443 */
445 msg_t rdymsg;
446
448 chDbgCheck((mbp != NULL) && (msgp != NULL));
449
450 do {
451 /* If the mailbox is in reset state then returns immediately.*/
452 if (mbp->reset) {
453 return MSG_RESET;
454 }
455
456 /* Is there a message in queue? if so then fetch.*/
457 if (chMBGetUsedCountI(mbp) > (size_t)0) {
458 *msgp = *mbp->rdptr++;
459 if (mbp->rdptr >= mbp->top) {
460 mbp->rdptr = mbp->buffer;
461 }
462 mbp->cnt--;
463
464 /* If there is a writer waiting then makes it ready.*/
467
468 return MSG_OK;
469 }
470
471 /* No message in the queue, waiting for a message to become available.*/
472 rdymsg = chThdEnqueueTimeoutS(&mbp->qr, timeout);
473 } while (rdymsg == MSG_OK);
474
475 return rdymsg;
476}
477
478/**
479 * @brief Retrieves a message from a mailbox.
480 * @details This variant is non-blocking, the function returns a timeout
481 * condition if the queue is empty.
482 *
483 * @param[in] mbp the pointer to an initialized @p mailbox_t object
484 * @param[out] msgp pointer to a message variable for the received message
485 * @return The operation status.
486 * @retval MSG_OK if a message has been correctly fetched.
487 * @retval MSG_RESET if the mailbox has been reset.
488 * @retval MSG_TIMEOUT if the mailbox is empty and a message cannot be
489 * fetched.
490 *
491 * @iclass
492 */
494
496 chDbgCheck((mbp != NULL) && (msgp != NULL));
497
498 /* If the mailbox is in reset state then returns immediately.*/
499 if (mbp->reset) {
500 return MSG_RESET;
501 }
502
503 /* Is there a message in queue? if so then fetch.*/
504 if (chMBGetUsedCountI(mbp) > (size_t)0) {
505 *msgp = *mbp->rdptr++;
506 if (mbp->rdptr >= mbp->top) {
507 mbp->rdptr = mbp->buffer;
508 }
509 mbp->cnt--;
510
511 /* If there is a writer waiting then makes it ready.*/
513
514 return MSG_OK;
515 }
516
517 /* No message, immediate timeout.*/
518 return MSG_TIMEOUT;
519}
520#endif /* CH_CFG_USE_MAILBOXES == TRUE */
521
522/** @} */
#define chThdQueueObjectInit(tqp)
Initializes a threads queue object.
#define chSysUnlock()
Leaves the kernel lock state.
#define chSysLock()
Enters the kernel lock state.
#define chDbgCheck(c)
Function parameters check.
Definition chdebug.h:118
#define chDbgCheckClassS()
Definition chdebug.h:100
#define chDbgCheckClassI()
Definition chdebug.h:99
int32_t msg_t
Definition chearly.h:88
void chMBObjectInit(mailbox_t *mbp, msg_t *buf, size_t n)
Initializes a mailbox_t object.
Definition chmboxes.c:87
msg_t chMBFetchTimeout(mailbox_t *mbp, msg_t *msgp, sysinterval_t timeout)
Retrieves a message from a mailbox.
Definition chmboxes.c:415
msg_t chMBPostTimeout(mailbox_t *mbp, msg_t msg, sysinterval_t timeout)
Posts a message into a mailbox.
Definition chmboxes.c:165
msg_t chMBPostI(mailbox_t *mbp, msg_t msg)
Posts a message into a mailbox.
Definition chmboxes.c:243
static size_t chMBGetUsedCountI(const mailbox_t *mbp)
Returns the number of used message slots into a mailbox.
Definition chmboxes.h:152
msg_t chMBPostAheadTimeout(mailbox_t *mbp, msg_t msg, sysinterval_t timeout)
Posts an high priority message into a mailbox.
Definition chmboxes.c:290
static size_t chMBGetFreeCountI(const mailbox_t *mbp)
Returns the number of free message slots into a mailbox.
Definition chmboxes.h:167
void chMBResetI(mailbox_t *mbp)
Resets a mailbox_t object.
Definition chmboxes.c:133
msg_t chMBPostTimeoutS(mailbox_t *mbp, msg_t msg, sysinterval_t timeout)
Posts a message into a mailbox.
Definition chmboxes.c:194
msg_t chMBPostAheadTimeoutS(mailbox_t *mbp, msg_t msg, sysinterval_t timeout)
Posts an high priority message into a mailbox.
Definition chmboxes.c:319
msg_t chMBFetchI(mailbox_t *mbp, msg_t *msgp)
Retrieves a message from a mailbox.
Definition chmboxes.c:493
msg_t chMBPostAheadI(mailbox_t *mbp, msg_t msg)
Posts an high priority message into a mailbox.
Definition chmboxes.c:368
msg_t chMBFetchTimeoutS(mailbox_t *mbp, msg_t *msgp, sysinterval_t timeout)
Retrieves a message from a mailbox.
Definition chmboxes.c:444
void chMBReset(mailbox_t *mbp)
Resets a mailbox_t object.
Definition chmboxes.c:113
void chSchRescheduleS(void)
Performs a reschedule if a higher priority thread is runnable.
Definition chschd.c:458
#define MSG_OK
Normal wakeup message.
Definition chschd.h:39
#define MSG_TIMEOUT
Wakeup caused by a timeout condition.
Definition chschd.h:40
#define MSG_RESET
Wakeup caused by a reset condition.
Definition chschd.h:42
msg_t chThdEnqueueTimeoutS(threads_queue_t *tqp, sysinterval_t timeout)
Enqueues the caller thread on a threads queue object.
Definition chthreads.c:868
void chThdDequeueNextI(threads_queue_t *tqp, msg_t msg)
Dequeues and wakes up one thread from the threads queue object, if any.
Definition chthreads.c:889
void chThdDequeueAllI(threads_queue_t *tqp, msg_t msg)
Dequeues and wakes up all threads from the threads queue object.
Definition chthreads.c:904
uint64_t sysinterval_t
Type of time interval.
Definition chtime.h:119
Structure representing a mailbox object.
Definition chmboxes.h:52
threads_queue_t qw
Queued writers.
Definition chmboxes.h:61
msg_t * wrptr
Write pointer.
Definition chmboxes.h:57
threads_queue_t qr
Queued readers.
Definition chmboxes.h:62
bool reset
True in reset state.
Definition chmboxes.h:60
msg_t * buffer
Pointer to the mailbox buffer.
Definition chmboxes.h:53
size_t cnt
Messages in queue.
Definition chmboxes.h:59
msg_t * rdptr
Read pointer.
Definition chmboxes.h:58
msg_t * top
Pointer to the location after the buffer.
Definition chmboxes.h:55