        -:    0:Source:../../../os/rt/src/chqueues.c
        -:    0:Programs:17
        -:    1:/*
        -:    2:    ChibiOS - Copyright (C) 2006..2015 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    chqueues.c
        -:   22: * @brief   I/O Queues code.
        -:   23: *
        -:   24: * @addtogroup io_queues
        -:   25: * @details ChibiOS/RT queues are mostly used in serial-like device drivers.
        -:   26: *          The device drivers are usually designed to have a lower side
        -:   27: *          (lower driver, it is usually an interrupt service routine) and an
        -:   28: *          upper side (upper driver, accessed by the application threads).<br>
        -:   29: *          There are several kind of queues:<br>
        -:   30: *          - <b>Input queue</b>, unidirectional queue where the writer is the
        -:   31: *            lower side and the reader is the upper side.
        -:   32: *          - <b>Output queue</b>, unidirectional queue where the writer is the
        -:   33: *            upper side and the reader is the lower side.
        -:   34: *          - <b>Full duplex queue</b>, bidirectional queue. Full duplex queues
        -:   35: *            are implemented by pairing an input queue and an output queue
        -:   36: *            together.
        -:   37: *          .
        -:   38: * @pre     In order to use the I/O queues the @p CH_CFG_USE_QUEUES option must
        -:   39: *          be enabled in @p chconf.h.
        -:   40: * @{
        -:   41: */
        -:   42:
        -:   43:#include "ch.h"
        -:   44:
        -:   45:#if (CH_CFG_USE_QUEUES == TRUE) || defined(__DOXYGEN__)
        -:   46:
        -:   47:/*===========================================================================*/
        -:   48:/* Module local definitions.                                                 */
        -:   49:/*===========================================================================*/
        -:   50:
        -:   51:/*===========================================================================*/
        -:   52:/* Module exported variables.                                                */
        -:   53:/*===========================================================================*/
        -:   54:
        -:   55:/*===========================================================================*/
        -:   56:/* Module local types.                                                       */
        -:   57:/*===========================================================================*/
        -:   58:
        -:   59:/*===========================================================================*/
        -:   60:/* Module local variables.                                                   */
        -:   61:/*===========================================================================*/
        -:   62:
        -:   63:/*===========================================================================*/
        -:   64:/* Module local functions.                                                   */
        -:   65:/*===========================================================================*/
        -:   66:
        -:   67:/*===========================================================================*/
        -:   68:/* Module exported functions.                                                */
        -:   69:/*===========================================================================*/
        -:   70:
        -:   71:/**
        -:   72: * @brief   Initializes an input queue.
        -:   73: * @details A Semaphore is internally initialized and works as a counter of
        -:   74: *          the bytes contained in the queue.
        -:   75: * @note    The callback is invoked from within the S-Locked system state,
        -:   76: *          see @ref system_states.
        -:   77: *
        -:   78: * @param[out] iqp      pointer to an @p input_queue_t structure
        -:   79: * @param[in] bp        pointer to a memory area allocated as queue buffer
        -:   80: * @param[in] size      size of the queue buffer
        -:   81: * @param[in] infy      pointer to a callback function that is invoked when
        -:   82: *                      data is read from the queue. The value can be @p NULL.
        -:   83: * @param[in] link      application defined pointer
        -:   84: *
        -:   85: * @init
        -:   86: */
function chIQObjectInit called 2 returned 100% blocks executed 100%
        2:   87:void chIQObjectInit(input_queue_t *iqp, uint8_t *bp, size_t size,
        -:   88:                    qnotify_t infy, void *link) {
        -:   89:
        2:   90:  chThdQueueObjectInit(&iqp->q_waiting);
call    0 returned 100%
        2:   91:  iqp->q_counter = 0;
        2:   92:  iqp->q_buffer  = bp;
        2:   93:  iqp->q_rdptr   = bp;
        2:   94:  iqp->q_wrptr   = bp;
        2:   95:  iqp->q_top     = bp + size;
        2:   96:  iqp->q_notify  = infy;
        2:   97:  iqp->q_link    = link;
        2:   98:}
        -:   99:
        -:  100:/**
        -:  101: * @brief   Resets an input queue.
        -:  102: * @details All the data in the input queue is erased and lost, any waiting
        -:  103: *          thread is resumed with status @p Q_RESET.
        -:  104: * @note    A reset operation can be used by a low level driver in order to
        -:  105: *          obtain immediate attention from the high level layers.
        -:  106: *
        -:  107: * @param[in] iqp       pointer to an @p input_queue_t structure
        -:  108: *
        -:  109: * @iclass
        -:  110: */
function chIQResetI called 1 returned 100% blocks executed 100%
        1:  111:void chIQResetI(input_queue_t *iqp) {
        -:  112:
        -:  113:  chDbgCheckClassI();
        -:  114:
        1:  115:  iqp->q_rdptr = iqp->q_buffer;
        1:  116:  iqp->q_wrptr = iqp->q_buffer;
        1:  117:  iqp->q_counter = 0;
        1:  118:  chThdDequeueAllI(&iqp->q_waiting, Q_RESET);
call    0 returned 100%
        1:  119:}
        -:  120:
        -:  121:/**
        -:  122: * @brief   Input queue write.
        -:  123: * @details A byte value is written into the low end of an input queue.
        -:  124: *
        -:  125: * @param[in] iqp       pointer to an @p input_queue_t structure
        -:  126: * @param[in] b         the byte value to be written in the queue
        -:  127: * @return              The operation status.
        -:  128: * @retval Q_OK         if the operation has been completed with success.
        -:  129: * @retval Q_FULL       if the queue is full and the operation cannot be
        -:  130: *                      completed.
        -:  131: *
        -:  132: * @iclass
        -:  133: */
function chIQPutI called 35801698 returned 100% blocks executed 100%
 35801698:  134:msg_t chIQPutI(input_queue_t *iqp, uint8_t b) {
        -:  135:
        -:  136:  chDbgCheckClassI();
        -:  137:
 35801698:  138:  if (chIQIsFullI(iqp)) {
call    0 returned 100%
branch  1 taken 1% (fallthrough)
branch  2 taken 99%
        1:  139:    return Q_FULL;
unconditional  0 taken 100%
        -:  140:  }
        -:  141:
 35801697:  142:  iqp->q_counter++;
 35801697:  143:  *iqp->q_wrptr++ = b;
 35801697:  144:  if (iqp->q_wrptr >= iqp->q_top) {
branch  0 taken 6% (fallthrough)
branch  1 taken 94%
  2237608:  145:    iqp->q_wrptr = iqp->q_buffer;
unconditional  0 taken 100%
        -:  146:  }
        -:  147:
 35801697:  148:  chThdDequeueNextI(&iqp->q_waiting, Q_OK);
call    0 returned 100%
        -:  149:
 35801697:  150:  return Q_OK;
unconditional  0 taken 100%
        -:  151:}
        -:  152:
        -:  153:/**
        -:  154: * @brief   Input queue read with timeout.
        -:  155: * @details This function reads a byte value from an input queue. If the queue
        -:  156: *          is empty then the calling thread is suspended until a byte arrives
        -:  157: *          in the queue or a timeout occurs.
        -:  158: * @note    The callback is invoked before reading the character from the
        -:  159: *          buffer or before entering the state @p CH_STATE_WTQUEUE.
        -:  160: *
        -:  161: * @param[in] iqp       pointer to an @p input_queue_t structure
        -:  162: * @param[in] timeout   the number of ticks before the operation timeouts,
        -:  163: *                      the following special values are allowed:
        -:  164: *                      - @a TIME_IMMEDIATE immediate timeout.
        -:  165: *                      - @a TIME_INFINITE no timeout.
        -:  166: *                      .
        -:  167: * @return              A byte value from the queue.
        -:  168: * @retval Q_TIMEOUT    if the specified time expired.
        -:  169: * @retval Q_RESET      if the queue has been reset.
        -:  170: *
        -:  171: * @api
        -:  172: */
function chIQGetTimeout called 35801690 returned 100% blocks executed 100%
 35801690:  173:msg_t chIQGetTimeout(input_queue_t *iqp, systime_t timeout) {
        -:  174:  uint8_t b;
        -:  175:
 35801690:  176:  chSysLock();
call    0 returned 100%
 35801690:  177:  if (iqp->q_notify != NULL) {
branch  0 taken 1% (fallthrough)
branch  1 taken 99%
        6:  178:    iqp->q_notify(iqp);
call    0 returned 100%
unconditional  1 taken 100%
        -:  179:  }
        -:  180:
 71603380:  181:  while (chIQIsEmptyI(iqp)) {
unconditional  0 taken 100%
call    1 returned 100%
branch  2 taken 1%
branch  3 taken 99% (fallthrough)
        2:  182:    msg_t msg = chThdEnqueueTimeoutS(&iqp->q_waiting, timeout);
call    0 returned 100%
        2:  183:    if (msg < Q_OK) {
branch  0 taken 100% (fallthrough)
branch  1 taken 0%
        2:  184:      chSysUnlock();
call    0 returned 100%
        2:  185:      return msg;
unconditional  0 taken 100%
        -:  186:    }
        -:  187:  }
        -:  188:
 35801688:  189:  iqp->q_counter--;
 35801688:  190:  b = *iqp->q_rdptr++;
 35801688:  191:  if (iqp->q_rdptr >= iqp->q_top) {
branch  0 taken 6% (fallthrough)
branch  1 taken 94%
  2237606:  192:    iqp->q_rdptr = iqp->q_buffer;
unconditional  0 taken 100%
        -:  193:  }
 35801688:  194:  chSysUnlock();
call    0 returned 100%
        -:  195:
 35801688:  196:  return (msg_t)b;
unconditional  0 taken 100%
        -:  197:}
        -:  198:
        -:  199:/**
        -:  200: * @brief   Input queue read with timeout.
        -:  201: * @details The function reads data from an input queue into a buffer. The
        -:  202: *          operation completes when the specified amount of data has been
        -:  203: *          transferred or after the specified timeout or if the queue has
        -:  204: *          been reset.
        -:  205: * @note    The function is not atomic, if you need atomicity it is suggested
        -:  206: *          to use a semaphore or a mutex for mutual exclusion.
        -:  207: * @note    The callback is invoked before reading each character from the
        -:  208: *          buffer or before entering the state @p CH_STATE_WTQUEUE.
        -:  209: *
        -:  210: * @param[in] iqp       pointer to an @p input_queue_t structure
        -:  211: * @param[out] bp       pointer to the data buffer
        -:  212: * @param[in] n         the maximum amount of data to be transferred, the
        -:  213: *                      value 0 is reserved
        -:  214: * @param[in] timeout   the number of ticks before the operation timeouts,
        -:  215: *                      the following special values are allowed:
        -:  216: *                      - @a TIME_IMMEDIATE immediate timeout.
        -:  217: *                      - @a TIME_INFINITE no timeout.
        -:  218: *                      .
        -:  219: * @return              The number of bytes effectively transferred.
        -:  220: *
        -:  221: * @api
        -:  222: */
function chIQReadTimeout called 3 returned 100% blocks executed 100%
        3:  223:size_t chIQReadTimeout(input_queue_t *iqp, uint8_t *bp,
        -:  224:                       size_t n, systime_t timeout) {
        3:  225:  qnotify_t nfy = iqp->q_notify;
        3:  226:  size_t r = 0;
unconditional  0 taken 100%
        -:  227:
        -:  228:  chDbgCheck(n > 0U);
        -:  229:
        3:  230:  chSysLock();
call    0 returned 100%
unconditional  1 taken 100%
        -:  231:  while (true) {
        9:  232:    if (nfy != NULL) {
branch  0 taken 100% (fallthrough)
branch  1 taken 0%
        9:  233:      nfy(iqp);
call    0 returned 100%
unconditional  1 taken 100%
        -:  234:    }
        -:  235:
       18:  236:    while (chIQIsEmptyI(iqp)) {
unconditional  0 taken 100%
call    1 returned 100%
branch  2 taken 11%
branch  3 taken 89% (fallthrough)
        1:  237:      if (chThdEnqueueTimeoutS(&iqp->q_waiting, timeout) != Q_OK) {
call    0 returned 100%
branch  1 taken 100% (fallthrough)
branch  2 taken 0%
        1:  238:        chSysUnlock();
call    0 returned 100%
        1:  239:        return r;
unconditional  0 taken 100%
        -:  240:      }
        -:  241:    }
        -:  242:
        8:  243:    iqp->q_counter--;
        8:  244:    *bp++ = *iqp->q_rdptr++;
        8:  245:    if (iqp->q_rdptr >= iqp->q_top) {
branch  0 taken 25% (fallthrough)
branch  1 taken 75%
        2:  246:      iqp->q_rdptr = iqp->q_buffer;
unconditional  0 taken 100%
        -:  247:    }
        8:  248:    chSysUnlock(); /* Gives a preemption chance in a controlled point.*/
call    0 returned 100%
        -:  249:
        8:  250:    r++;
        8:  251:    if (--n == 0U) {
branch  0 taken 25% (fallthrough)
branch  1 taken 75%
        2:  252:      return r;
unconditional  0 taken 100%
        -:  253:    }
        -:  254:
        6:  255:    chSysLock();
call    0 returned 100%
        6:  256:  }
unconditional  0 taken 100%
        -:  257:}
        -:  258:
        -:  259:/**
        -:  260: * @brief   Initializes an output queue.
        -:  261: * @details A Semaphore is internally initialized and works as a counter of
        -:  262: *          the free bytes in the queue.
        -:  263: * @note    The callback is invoked from within the S-Locked system state,
        -:  264: *          see @ref system_states.
        -:  265: *
        -:  266: * @param[out] oqp      pointer to an @p output_queue_t structure
        -:  267: * @param[in] bp        pointer to a memory area allocated as queue buffer
        -:  268: * @param[in] size      size of the queue buffer
        -:  269: * @param[in] onfy      pointer to a callback function that is invoked when
        -:  270: *                      data is written to the queue. The value can be @p NULL.
        -:  271: * @param[in] link      application defined pointer
        -:  272: *
        -:  273: * @init
        -:  274: */
function chOQObjectInit called 1 returned 100% blocks executed 100%
        1:  275:void chOQObjectInit(output_queue_t *oqp, uint8_t *bp, size_t size,
        -:  276:                    qnotify_t onfy, void *link) {
        -:  277:
        1:  278:  chThdQueueObjectInit(&oqp->q_waiting);
call    0 returned 100%
        1:  279:  oqp->q_counter = size;
        1:  280:  oqp->q_buffer  = bp;
        1:  281:  oqp->q_rdptr   = bp;
        1:  282:  oqp->q_wrptr   = bp;
        1:  283:  oqp->q_top     = bp + size;
        1:  284:  oqp->q_notify  = onfy;
        1:  285:  oqp->q_link    = link;
        1:  286:}
        -:  287:
        -:  288:/**
        -:  289: * @brief   Resets an output queue.
        -:  290: * @details All the data in the output queue is erased and lost, any waiting
        -:  291: *          thread is resumed with status @p Q_RESET.
        -:  292: * @note    A reset operation can be used by a low level driver in order to
        -:  293: *          obtain immediate attention from the high level layers.
        -:  294: *
        -:  295: * @param[in] oqp       pointer to an @p output_queue_t structure
        -:  296: *
        -:  297: * @iclass
        -:  298: */
function chOQResetI called 1 returned 100% blocks executed 100%
        1:  299:void chOQResetI(output_queue_t *oqp) {
        -:  300:
        -:  301:  chDbgCheckClassI();
        -:  302:
        1:  303:  oqp->q_rdptr = oqp->q_buffer;
        1:  304:  oqp->q_wrptr = oqp->q_buffer;
        1:  305:  oqp->q_counter = chQSizeX(oqp);
        1:  306:  chThdDequeueAllI(&oqp->q_waiting, Q_RESET);
call    0 returned 100%
        1:  307:}
        -:  308:
        -:  309:/**
        -:  310: * @brief   Output queue write with timeout.
        -:  311: * @details This function writes a byte value to an output queue. If the queue
        -:  312: *          is full then the calling thread is suspended until there is space
        -:  313: *          in the queue or a timeout occurs.
        -:  314: * @note    The callback is invoked after writing the character into the
        -:  315: *          buffer.
        -:  316: *
        -:  317: * @param[in] oqp       pointer to an @p output_queue_t structure
        -:  318: * @param[in] b         the byte value to be written in the queue
        -:  319: * @param[in] timeout   the number of ticks before the operation timeouts,
        -:  320: *                      the following special values are allowed:
        -:  321: *                      - @a TIME_IMMEDIATE immediate timeout.
        -:  322: *                      - @a TIME_INFINITE no timeout.
        -:  323: *                      .
        -:  324: * @return              The operation status.
        -:  325: * @retval Q_OK         if the operation succeeded.
        -:  326: * @retval Q_TIMEOUT    if the specified time expired.
        -:  327: * @retval Q_RESET      if the queue has been reset.
        -:  328: *
        -:  329: * @api
        -:  330: */
function chOQPutTimeout called 6 returned 100% blocks executed 100%
        6:  331:msg_t chOQPutTimeout(output_queue_t *oqp, uint8_t b, systime_t timeout) {
        -:  332:
        6:  333:  chSysLock();
call    0 returned 100%
        6:  334:  while (chOQIsFullI(oqp)) {
unconditional  0 taken 100%
call    1 returned 100%
branch  2 taken 33%
branch  3 taken 67% (fallthrough)
        2:  335:    msg_t msg = chThdEnqueueTimeoutS(&oqp->q_waiting, timeout);
call    0 returned 100%
        2:  336:    if (msg < Q_OK) {
branch  0 taken 100% (fallthrough)
branch  1 taken 0%
        2:  337:      chSysUnlock();
call    0 returned 100%
        2:  338:      return msg;
unconditional  0 taken 100%
        -:  339:    }
        -:  340:  }
        -:  341:
        4:  342:  oqp->q_counter--;
        4:  343:  *oqp->q_wrptr++ = b;
        4:  344:  if (oqp->q_wrptr >= oqp->q_top) {
branch  0 taken 25% (fallthrough)
branch  1 taken 75%
        1:  345:    oqp->q_wrptr = oqp->q_buffer;
unconditional  0 taken 100%
        -:  346:  }
        -:  347:
        4:  348:  if (oqp->q_notify != NULL) {
branch  0 taken 100% (fallthrough)
branch  1 taken 0%
        4:  349:    oqp->q_notify(oqp);
call    0 returned 100%
unconditional  1 taken 100%
        -:  350:  }
        4:  351:  chSysUnlock();
call    0 returned 100%
        -:  352:
        4:  353:  return Q_OK;
unconditional  0 taken 100%
        -:  354:}
        -:  355:
        -:  356:/**
        -:  357: * @brief   Output queue read.
        -:  358: * @details A byte value is read from the low end of an output queue.
        -:  359: *
        -:  360: * @param[in] oqp       pointer to an @p output_queue_t structure
        -:  361: * @return              The byte value from the queue.
        -:  362: * @retval Q_EMPTY      if the queue is empty.
        -:  363: *
        -:  364: * @iclass
        -:  365: */
function chOQGetI called 5 returned 100% blocks executed 100%
        5:  366:msg_t chOQGetI(output_queue_t *oqp) {
        -:  367:  uint8_t b;
        -:  368:
        -:  369:  chDbgCheckClassI();
        -:  370:
        5:  371:  if (chOQIsEmptyI(oqp)) {
call    0 returned 100%
branch  1 taken 20% (fallthrough)
branch  2 taken 80%
        1:  372:    return Q_EMPTY;
unconditional  0 taken 100%
        -:  373:  }
        -:  374:
        4:  375:  oqp->q_counter++;
        4:  376:  b = *oqp->q_rdptr++;
        4:  377:  if (oqp->q_rdptr >= oqp->q_top) {
branch  0 taken 25% (fallthrough)
branch  1 taken 75%
        1:  378:    oqp->q_rdptr = oqp->q_buffer;
unconditional  0 taken 100%
        -:  379:  }
        -:  380:
        4:  381:  chThdDequeueNextI(&oqp->q_waiting, Q_OK);
call    0 returned 100%
        -:  382:
        4:  383:  return (msg_t)b;
unconditional  0 taken 100%
        -:  384:}
        -:  385:
        -:  386:/**
        -:  387: * @brief   Output queue write with timeout.
        -:  388: * @details The function writes data from a buffer to an output queue. The
        -:  389: *          operation completes when the specified amount of data has been
        -:  390: *          transferred or after the specified timeout or if the queue has
        -:  391: *          been reset.
        -:  392: * @note    The function is not atomic, if you need atomicity it is suggested
        -:  393: *          to use a semaphore or a mutex for mutual exclusion.
        -:  394: * @note    The callback is invoked after writing each character into the
        -:  395: *          buffer.
        -:  396: *
        -:  397: * @param[in] oqp       pointer to an @p output_queue_t structure
        -:  398: * @param[in] bp        pointer to the data buffer
        -:  399: * @param[in] n         the maximum amount of data to be transferred, the
        -:  400: *                      value 0 is reserved
        -:  401: * @param[in] timeout   the number of ticks before the operation timeouts,
        -:  402: *                      the following special values are allowed:
        -:  403: *                      - @a TIME_IMMEDIATE immediate timeout.
        -:  404: *                      - @a TIME_INFINITE no timeout.
        -:  405: *                      .
        -:  406: * @return              The number of bytes effectively transferred.
        -:  407: *
        -:  408: * @api
        -:  409: */
function chOQWriteTimeout called 3 returned 100% blocks executed 100%
        3:  410:size_t chOQWriteTimeout(output_queue_t *oqp, const uint8_t *bp,
        -:  411:                        size_t n, systime_t timeout) {
        3:  412:  qnotify_t nfy = oqp->q_notify;
        3:  413:  size_t w = 0;
unconditional  0 taken 100%
        -:  414:
        -:  415:  chDbgCheck(n > 0U);
        -:  416:
        3:  417:  chSysLock();
call    0 returned 100%
unconditional  1 taken 100%
        -:  418:  while (true) {
       18:  419:    while (chOQIsFullI(oqp)) {
unconditional  0 taken 100%
call    1 returned 100%
branch  2 taken 11%
branch  3 taken 89% (fallthrough)
        1:  420:      if (chThdEnqueueTimeoutS(&oqp->q_waiting, timeout) != Q_OK) {
call    0 returned 100%
branch  1 taken 100% (fallthrough)
branch  2 taken 0%
        1:  421:        chSysUnlock();
call    0 returned 100%
        1:  422:        return w;
unconditional  0 taken 100%
        -:  423:      }
        -:  424:    }
        -:  425:    
        8:  426:    oqp->q_counter--;
        8:  427:    *oqp->q_wrptr++ = *bp++;
        8:  428:    if (oqp->q_wrptr >= oqp->q_top) {
branch  0 taken 25% (fallthrough)
branch  1 taken 75%
        2:  429:      oqp->q_wrptr = oqp->q_buffer;
unconditional  0 taken 100%
        -:  430:    }
        -:  431:
        8:  432:    if (nfy != NULL) {
branch  0 taken 100% (fallthrough)
branch  1 taken 0%
        8:  433:      nfy(oqp);
call    0 returned 100%
unconditional  1 taken 100%
        -:  434:    }
        8:  435:    chSysUnlock(); /* Gives a preemption chance in a controlled point.*/
call    0 returned 100%
        -:  436:
        8:  437:    w++;
        8:  438:    if (--n == 0U) {
branch  0 taken 25% (fallthrough)
branch  1 taken 75%
        2:  439:      return w;
unconditional  0 taken 100%
        -:  440:    }
        6:  441:    chSysLock();
call    0 returned 100%
        6:  442:  }
unconditional  0 taken 100%
        -:  443:}
        -:  444:#endif  /* CH_CFG_USE_QUEUES == TRUE */
        -:  445:
        -:  446:/** @} */
