ChibiOS/RT
2.5.1
chmboxes.c
Go to the documentation of this file.
00001 /*
00002     ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
00003                  2011,2012 Giovanni Di Sirio.
00004 
00005     This file is part of ChibiOS/RT.
00006 
00007     ChibiOS/RT is free software; you can redistribute it and/or modify
00008     it under the terms of the GNU General Public License as published by
00009     the Free Software Foundation; either version 3 of the License, or
00010     (at your option) any later version.
00011 
00012     ChibiOS/RT is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015     GNU General Public License for more details.
00016 
00017     You should have received a copy of the GNU General Public License
00018     along with this program.  If not, see <http://www.gnu.org/licenses/>.
00019 */
00020 
00021 /**
00022  * @file    chmboxes.c
00023  * @brief   Mailboxes code.
00024  *
00025  * @addtogroup mailboxes
00026  * @details Asynchronous messages.
00027  *          <h2>Operation mode</h2>
00028  *          A mailbox is an asynchronous communication mechanism.<br>
00029  *          Operations defined for mailboxes:
00030  *          - <b>Post</b>: Posts a message on the mailbox in FIFO order.
00031  *          - <b>Post Ahead</b>: Posts a message on the mailbox with urgent
00032  *            priority.
00033  *          - <b>Fetch</b>: A message is fetched from the mailbox and removed
00034  *            from the queue.
00035  *          - <b>Reset</b>: The mailbox is emptied and all the stored messages
00036  *            are lost.
00037  *          .
00038  *          A message is a variable of type msg_t that is guaranteed to have
00039  *          the same size of and be compatible with (data) pointers (anyway an
00040  *          explicit cast is needed).
00041  *          If larger messages need to be exchanged then a pointer to a
00042  *          structure can be posted in the mailbox but the posting side has
00043  *          no predefined way to know when the message has been processed. A
00044  *          possible approach is to allocate memory (from a memory pool for
00045  *          example) from the posting side and free it on the fetching side.
00046  *          Another approach is to set a "done" flag into the structure pointed
00047  *          by the message.
00048  * @pre     In order to use the mailboxes APIs the @p CH_USE_MAILBOXES option
00049  *          must be enabled in @p chconf.h.
00050  * @{
00051  */
00052 
00053 #include "ch.h"
00054 
00055 #if CH_USE_MAILBOXES || defined(__DOXYGEN__)
00056 /**
00057  * @brief   Initializes a Mailbox object.
00058  *
00059  * @param[out] mbp      the pointer to the Mailbox structure to be initialized
00060  * @param[in] buf       pointer to the messages buffer as an array of @p msg_t
00061  * @param[in] n         number of elements in the buffer array
00062  *
00063  * @init
00064  */
00065 void chMBInit(Mailbox *mbp, msg_t *buf, cnt_t n) {
00066 
00067   chDbgCheck((mbp != NULL) && (buf != NULL) && (n > 0), "chMBInit");
00068 
00069   mbp->mb_buffer = mbp->mb_wrptr = mbp->mb_rdptr = buf;
00070   mbp->mb_top = &buf[n];
00071   chSemInit(&mbp->mb_emptysem, n);
00072   chSemInit(&mbp->mb_fullsem, 0);
00073 }
00074 
00075 /**
00076  * @brief   Resets a Mailbox object.
00077  * @details All the waiting threads are resumed with status @p RDY_RESET and
00078  *          the queued messages are lost.
00079  *
00080  * @param[in] mbp       the pointer to an initialized Mailbox object
00081  *
00082  * @api
00083  */
00084 void chMBReset(Mailbox *mbp) {
00085 
00086   chDbgCheck(mbp != NULL, "chMBReset");
00087 
00088   chSysLock();
00089   mbp->mb_wrptr = mbp->mb_rdptr = mbp->mb_buffer;
00090   chSemResetI(&mbp->mb_emptysem, mbp->mb_top - mbp->mb_buffer);
00091   chSemResetI(&mbp->mb_fullsem, 0);
00092   chSchRescheduleS();
00093   chSysUnlock();
00094 }
00095 
00096 /**
00097  * @brief   Posts a message into a mailbox.
00098  * @details The invoking thread waits until a empty slot in the mailbox becomes
00099  *          available or the specified time runs out.
00100  *
00101  * @param[in] mbp       the pointer to an initialized Mailbox object
00102  * @param[in] msg       the message to be posted on the mailbox
00103  * @param[in] time      the number of ticks before the operation timeouts,
00104  *                      the following special values are allowed:
00105  *                      - @a TIME_IMMEDIATE immediate timeout.
00106  *                      - @a TIME_INFINITE no timeout.
00107  *                      .
00108  * @return              The operation status.
00109  * @retval RDY_OK       if a message has been correctly posted.
00110  * @retval RDY_RESET    if the mailbox has been reset while waiting.
00111  * @retval RDY_TIMEOUT  if the operation has timed out.
00112  *
00113  * @api
00114  */
00115 msg_t chMBPost(Mailbox *mbp, msg_t msg, systime_t time) {
00116   msg_t rdymsg;
00117 
00118   chSysLock();
00119   rdymsg = chMBPostS(mbp, msg, time);
00120   chSysUnlock();
00121   return rdymsg;
00122 }
00123 
00124 /**
00125  * @brief   Posts a message into a mailbox.
00126  * @details The invoking thread waits until a empty slot in the mailbox becomes
00127  *          available or the specified time runs out.
00128  *
00129  * @param[in] mbp       the pointer to an initialized Mailbox object
00130  * @param[in] msg       the message to be posted on the mailbox
00131  * @param[in] time      the number of ticks before the operation timeouts,
00132  *                      the following special values are allowed:
00133  *                      - @a TIME_IMMEDIATE immediate timeout.
00134  *                      - @a TIME_INFINITE no timeout.
00135  *                      .
00136  * @return              The operation status.
00137  * @retval RDY_OK       if a message has been correctly posted.
00138  * @retval RDY_RESET    if the mailbox has been reset while waiting.
00139  * @retval RDY_TIMEOUT  if the operation has timed out.
00140  *
00141  * @sclass
00142  */
00143 msg_t chMBPostS(Mailbox *mbp, msg_t msg, systime_t time) {
00144   msg_t rdymsg;
00145 
00146   chDbgCheckClassS();
00147   chDbgCheck(mbp != NULL, "chMBPostS");
00148 
00149   rdymsg = chSemWaitTimeoutS(&mbp->mb_emptysem, time);
00150   if (rdymsg == RDY_OK) {
00151     *mbp->mb_wrptr++ = msg;
00152     if (mbp->mb_wrptr >= mbp->mb_top)
00153       mbp->mb_wrptr = mbp->mb_buffer;
00154     chSemSignalI(&mbp->mb_fullsem);
00155     chSchRescheduleS();
00156   }
00157   return rdymsg;
00158 }
00159 
00160 /**
00161  * @brief   Posts a message into a mailbox.
00162  * @details This variant is non-blocking, the function returns a timeout
00163  *          condition if the queue is full.
00164  *
00165  * @param[in] mbp       the pointer to an initialized Mailbox object
00166  * @param[in] msg       the message to be posted on the mailbox
00167  * @return              The operation status.
00168  * @retval RDY_OK       if a message has been correctly posted.
00169  * @retval RDY_TIMEOUT  if the mailbox is full and the message cannot be
00170  *                      posted.
00171  *
00172  * @iclass
00173  */
00174 msg_t chMBPostI(Mailbox *mbp, msg_t msg) {
00175 
00176   chDbgCheckClassI();
00177   chDbgCheck(mbp != NULL, "chMBPostI");
00178 
00179   if (chSemGetCounterI(&mbp->mb_emptysem) <= 0)
00180     return RDY_TIMEOUT;
00181   chSemFastWaitI(&mbp->mb_emptysem);
00182   *mbp->mb_wrptr++ = msg;
00183   if (mbp->mb_wrptr >= mbp->mb_top)
00184     mbp->mb_wrptr = mbp->mb_buffer;
00185   chSemSignalI(&mbp->mb_fullsem);
00186   return RDY_OK;
00187 }
00188 
00189 /**
00190  * @brief   Posts an high priority message into a mailbox.
00191  * @details The invoking thread waits until a empty slot in the mailbox becomes
00192  *          available or the specified time runs out.
00193  *
00194  * @param[in] mbp       the pointer to an initialized Mailbox object
00195  * @param[in] msg       the message to be posted on the mailbox
00196  * @param[in] time      the number of ticks before the operation timeouts,
00197  *                      the following special values are allowed:
00198  *                      - @a TIME_IMMEDIATE immediate timeout.
00199  *                      - @a TIME_INFINITE no timeout.
00200  *                      .
00201  * @return              The operation status.
00202  * @retval RDY_OK       if a message has been correctly posted.
00203  * @retval RDY_RESET    if the mailbox has been reset while waiting.
00204  * @retval RDY_TIMEOUT  if the operation has timed out.
00205  *
00206  * @api
00207  */
00208 msg_t chMBPostAhead(Mailbox *mbp, msg_t msg, systime_t time) {
00209   msg_t rdymsg;
00210 
00211   chSysLock();
00212   rdymsg = chMBPostAheadS(mbp, msg, time);
00213   chSysUnlock();
00214   return rdymsg;
00215 }
00216 
00217 /**
00218  * @brief   Posts an high priority message into a mailbox.
00219  * @details The invoking thread waits until a empty slot in the mailbox becomes
00220  *          available or the specified time runs out.
00221  *
00222  * @param[in] mbp       the pointer to an initialized Mailbox object
00223  * @param[in] msg       the message to be posted on the mailbox
00224  * @param[in] time      the number of ticks before the operation timeouts,
00225  *                      the following special values are allowed:
00226  *                      - @a TIME_IMMEDIATE immediate timeout.
00227  *                      - @a TIME_INFINITE no timeout.
00228  *                      .
00229  * @return              The operation status.
00230  * @retval RDY_OK       if a message has been correctly posted.
00231  * @retval RDY_RESET    if the mailbox has been reset while waiting.
00232  * @retval RDY_TIMEOUT  if the operation has timed out.
00233  *
00234  * @sclass
00235  */
00236 msg_t chMBPostAheadS(Mailbox *mbp, msg_t msg, systime_t time) {
00237   msg_t rdymsg;
00238 
00239   chDbgCheckClassS();
00240   chDbgCheck(mbp != NULL, "chMBPostAheadS");
00241 
00242   rdymsg = chSemWaitTimeoutS(&mbp->mb_emptysem, time);
00243   if (rdymsg == RDY_OK) {
00244     if (--mbp->mb_rdptr < mbp->mb_buffer)
00245       mbp->mb_rdptr = mbp->mb_top - 1;
00246     *mbp->mb_rdptr = msg;
00247     chSemSignalI(&mbp->mb_fullsem);
00248     chSchRescheduleS();
00249   }
00250   return rdymsg;
00251 }
00252 
00253 /**
00254  * @brief   Posts an high priority message into a mailbox.
00255  * @details This variant is non-blocking, the function returns a timeout
00256  *          condition if the queue is full.
00257  *
00258  * @param[in] mbp       the pointer to an initialized Mailbox object
00259  * @param[in] msg       the message to be posted on the mailbox
00260  * @return              The operation status.
00261  * @retval RDY_OK       if a message has been correctly posted.
00262  * @retval RDY_TIMEOUT  if the mailbox is full and the message cannot be
00263  *                      posted.
00264  *
00265  * @iclass
00266  */
00267 msg_t chMBPostAheadI(Mailbox *mbp, msg_t msg) {
00268 
00269   chDbgCheckClassI();
00270   chDbgCheck(mbp != NULL, "chMBPostAheadI");
00271 
00272   if (chSemGetCounterI(&mbp->mb_emptysem) <= 0)
00273     return RDY_TIMEOUT;
00274   chSemFastWaitI(&mbp->mb_emptysem);
00275   if (--mbp->mb_rdptr < mbp->mb_buffer)
00276     mbp->mb_rdptr = mbp->mb_top - 1;
00277   *mbp->mb_rdptr = msg;
00278   chSemSignalI(&mbp->mb_fullsem);
00279   return RDY_OK;
00280 }
00281 
00282 /**
00283  * @brief   Retrieves a message from a mailbox.
00284  * @details The invoking thread waits until a message is posted in the mailbox
00285  *          or the specified time runs out.
00286  *
00287  * @param[in] mbp       the pointer to an initialized Mailbox object
00288  * @param[out] msgp     pointer to a message variable for the received message
00289  * @param[in] time      the number of ticks before the operation timeouts,
00290  *                      the following special values are allowed:
00291  *                      - @a TIME_IMMEDIATE immediate timeout.
00292  *                      - @a TIME_INFINITE no timeout.
00293  *                      .
00294  * @return              The operation status.
00295  * @retval RDY_OK       if a message has been correctly fetched.
00296  * @retval RDY_RESET    if the mailbox has been reset while waiting.
00297  * @retval RDY_TIMEOUT  if the operation has timed out.
00298  *
00299  * @api
00300  */
00301 msg_t chMBFetch(Mailbox *mbp, msg_t *msgp, systime_t time) {
00302   msg_t rdymsg;
00303 
00304   chSysLock();
00305   rdymsg = chMBFetchS(mbp, msgp, time);
00306   chSysUnlock();
00307   return rdymsg;
00308 }
00309 
00310 /**
00311  * @brief   Retrieves a message from a mailbox.
00312  * @details The invoking thread waits until a message is posted in the mailbox
00313  *          or the specified time runs out.
00314  *
00315  * @param[in] mbp       the pointer to an initialized Mailbox object
00316  * @param[out] msgp     pointer to a message variable for the received message
00317  * @param[in] time      the number of ticks before the operation timeouts,
00318  *                      the following special values are allowed:
00319  *                      - @a TIME_IMMEDIATE immediate timeout.
00320  *                      - @a TIME_INFINITE no timeout.
00321  *                      .
00322  * @return              The operation status.
00323  * @retval RDY_OK       if a message has been correctly fetched.
00324  * @retval RDY_RESET    if the mailbox has been reset while waiting.
00325  * @retval RDY_TIMEOUT  if the operation has timed out.
00326  *
00327  * @sclass
00328  */
00329 msg_t chMBFetchS(Mailbox *mbp, msg_t *msgp, systime_t time) {
00330   msg_t rdymsg;
00331 
00332   chDbgCheckClassS();
00333   chDbgCheck((mbp != NULL) && (msgp != NULL), "chMBFetchS");
00334 
00335   rdymsg = chSemWaitTimeoutS(&mbp->mb_fullsem, time);
00336   if (rdymsg == RDY_OK) {
00337     *msgp = *mbp->mb_rdptr++;
00338     if (mbp->mb_rdptr >= mbp->mb_top)
00339       mbp->mb_rdptr = mbp->mb_buffer;
00340     chSemSignalI(&mbp->mb_emptysem);
00341     chSchRescheduleS();
00342   }
00343   return rdymsg;
00344 }
00345 
00346 /**
00347  * @brief   Retrieves a message from a mailbox.
00348  * @details This variant is non-blocking, the function returns a timeout
00349  *          condition if the queue is empty.
00350  *
00351  * @param[in] mbp       the pointer to an initialized Mailbox object
00352  * @param[out] msgp     pointer to a message variable for the received message
00353  * @return              The operation status.
00354  * @retval RDY_OK       if a message has been correctly fetched.
00355  * @retval RDY_TIMEOUT  if the mailbox is empty and a message cannot be
00356  *                      fetched.
00357  *
00358  * @iclass
00359  */
00360 msg_t chMBFetchI(Mailbox *mbp, msg_t *msgp) {
00361 
00362   chDbgCheckClassI();
00363   chDbgCheck((mbp != NULL) && (msgp != NULL), "chMBFetchI");
00364 
00365   if (chSemGetCounterI(&mbp->mb_fullsem) <= 0)
00366     return RDY_TIMEOUT;
00367   chSemFastWaitI(&mbp->mb_fullsem);
00368   *msgp = *mbp->mb_rdptr++;
00369   if (mbp->mb_rdptr >= mbp->mb_top)
00370     mbp->mb_rdptr = mbp->mb_buffer;
00371   chSemSignalI(&mbp->mb_emptysem);
00372   return RDY_OK;
00373 }
00374 #endif /* CH_USE_MAILBOXES */
00375 
00376 /** @} */