ChibiOS/RT  5.1.0
chmboxes.c
Go to the documentation of this file.
1 /*
2  ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio.
3 
4  This file is part of ChibiOS.
5 
6  ChibiOS is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 3 of the License, or
9  (at your option) any later version.
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 chmboxes.c
22  * @brief Mailboxes code.
23  *
24  * @addtogroup 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  */
87 void 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;
97  chThdQueueObjectInit(&mbp->qw);
98  chThdQueueObjectInit(&mbp->qr);
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  */
113 void chMBReset(mailbox_t *mbp) {
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  */
133 void chMBResetI(mailbox_t *mbp) {
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;
142  chThdDequeueAllI(&mbp->qw, MSG_RESET);
143  chThdDequeueAllI(&mbp->qr, MSG_RESET);
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  */
165 msg_t chMBPostTimeout(mailbox_t *mbp, msg_t msg, sysinterval_t timeout) {
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  */
194 msg_t chMBPostTimeoutS(mailbox_t *mbp, msg_t msg, sysinterval_t timeout) {
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.*/
215  chThdDequeueNextI(&mbp->qr, MSG_OK);
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  */
243 msg_t chMBPostI(mailbox_t *mbp, msg_t msg) {
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.*/
262  chThdDequeueNextI(&mbp->qr, MSG_OK);
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  */
290 msg_t chMBPostAheadTimeout(mailbox_t *mbp, msg_t msg, sysinterval_t timeout) {
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  */
319 msg_t chMBPostAheadTimeoutS(mailbox_t *mbp, msg_t msg, sysinterval_t timeout) {
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.*/
340  chThdDequeueNextI(&mbp->qr, MSG_OK);
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  */
368 msg_t chMBPostAheadI(mailbox_t *mbp, msg_t msg) {
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.*/
387  chThdDequeueNextI(&mbp->qr, MSG_OK);
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  */
415 msg_t chMBFetchTimeout(mailbox_t *mbp, msg_t *msgp, sysinterval_t timeout) {
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  */
444 msg_t chMBFetchTimeoutS(mailbox_t *mbp, msg_t *msgp, sysinterval_t timeout) {
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.*/
465  chThdDequeueNextI(&mbp->qw, MSG_OK);
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  */
493 msg_t chMBFetchI(mailbox_t *mbp, msg_t *msgp) {
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.*/
512  chThdDequeueNextI(&mbp->qw, MSG_OK);
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 /** @} */
static void chThdQueueObjectInit(threads_queue_t *tqp)
Initializes a threads queue object.
Definition: chthreads.h:392
msg_t chMBFetchTimeoutS(mailbox_t *mbp, msg_t *msgp, sysinterval_t timeout)
Retrieves a message from a mailbox.
Definition: chmboxes.c:444
void chDbgCheckClassS(void)
S-class functions context check.
Definition: chdebug.c:250
size_t cnt
Messages in queue.
Definition: chmboxes.h:63
msg_t chMBPostTimeoutS(mailbox_t *mbp, msg_t msg, sysinterval_t timeout)
Posts a message into a mailbox.
Definition: chmboxes.c:194
uint64_t sysinterval_t
Type of time interval.
Definition: chtime.h:150
static void chSysLock(void)
Enters the kernel lock state.
Definition: chsys.h:353
static size_t chMBGetFreeCountI(const mailbox_t *mbp)
Returns the number of free message slots into a mailbox.
Definition: chmboxes.h:171
void chThdDequeueAllI(threads_queue_t *tqp, msg_t msg)
Dequeues and wakes up all threads from the threads queue object.
Definition: chthreads.c:899
msg_t chThdEnqueueTimeoutS(threads_queue_t *tqp, sysinterval_t timeout)
Enqueues the caller thread on a threads queue object.
Definition: chthreads.c:864
static void chSysUnlock(void)
Leaves the kernel lock state.
Definition: chsys.h:365
msg_t chMBPostAheadI(mailbox_t *mbp, msg_t msg)
Posts an high priority message into a mailbox.
Definition: chmboxes.c:368
msg_t chMBFetchI(mailbox_t *mbp, msg_t *msgp)
Retrieves a message from a mailbox.
Definition: chmboxes.c:493
msg_t * top
Pointer to the location after the buffer.
Definition: chmboxes.h:59
void chDbgCheckClassI(void)
I-class functions context check.
Definition: chdebug.c:235
#define MSG_TIMEOUT
Wakeup caused by a timeout condition.
Definition: chschd.h:40
void chMBResetI(mailbox_t *mbp)
Resets a mailbox_t object.
Definition: chmboxes.c:133
void chSchRescheduleS(void)
Performs a reschedule if a higher priority thread is runnable.
Definition: chschd.c:456
static size_t chMBGetUsedCountI(const mailbox_t *mbp)
Returns the number of used message slots into a mailbox.
Definition: chmboxes.h:156
msg_t * buffer
Pointer to the mailbox buffer.
Definition: chmboxes.h:57
#define chDbgCheck(c)
Function parameters check.
Definition: chdebug.h:101
#define MSG_OK
Normal wakeup message.
Definition: chschd.h:39
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:884
void chMBReset(mailbox_t *mbp)
Resets a mailbox_t object.
Definition: chmboxes.c:113
msg_t chMBPostAheadTimeoutS(mailbox_t *mbp, msg_t msg, sysinterval_t timeout)
Posts an high priority message into a mailbox.
Definition: chmboxes.c:319
threads_queue_t qr
Queued readers.
Definition: chmboxes.h:66
msg_t * wrptr
Write pointer.
Definition: chmboxes.h:61
threads_queue_t qw
Queued writers.
Definition: chmboxes.h:65
msg_t chMBFetchTimeout(mailbox_t *mbp, msg_t *msgp, sysinterval_t timeout)
Retrieves a message from a mailbox.
Definition: chmboxes.c:415
msg_t chMBPostI(mailbox_t *mbp, msg_t msg)
Posts a message into a mailbox.
Definition: chmboxes.c:243
msg_t chMBPostTimeout(mailbox_t *mbp, msg_t msg, sysinterval_t timeout)
Posts a message into a mailbox.
Definition: chmboxes.c:165
bool reset
True in reset state.
Definition: chmboxes.h:64
msg_t chMBPostAheadTimeout(mailbox_t *mbp, msg_t msg, sysinterval_t timeout)
Posts an high priority message into a mailbox.
Definition: chmboxes.c:290
ChibiOS/RT main include file.
Structure representing a mailbox object.
Definition: chmboxes.h:56
msg_t * rdptr
Read pointer.
Definition: chmboxes.h:62
void chMBObjectInit(mailbox_t *mbp, msg_t *buf, size_t n)
Initializes a mailbox_t object.
Definition: chmboxes.c:87
#define MSG_RESET
Wakeup caused by a reset condition.
Definition: chschd.h:43