        -:    0:Source:../../../os/rt/src/chthreads.c
        -:    0:Programs:18
        -:    1:/*
        -:    2:    ChibiOS - Copyright (C) 2006..2016 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    chthreads.c
        -:   22: * @brief   Threads code.
        -:   23: *
        -:   24: * @addtogroup threads
        -:   25: * @details Threads related APIs and services.
        -:   26: *          <h2>Operation mode</h2>
        -:   27: *          A thread is an abstraction of an independent instructions flow.
        -:   28: *          In ChibiOS/RT a thread is represented by a "C" function owning
        -:   29: *          a processor context, state informations and a dedicated stack
        -:   30: *          area. In this scenario static variables are shared among all
        -:   31: *          threads while automatic variables are local to the thread.<br>
        -:   32: *          Operations defined for threads:
        -:   33: *          - <b>Create</b>, a thread is started on the specified thread
        -:   34: *            function. This operation is available in multiple variants,
        -:   35: *            both static and dynamic.
        -:   36: *          - <b>Exit</b>, a thread terminates by returning from its top
        -:   37: *            level function or invoking a specific API, the thread can
        -:   38: *            return a value that can be retrieved by other threads.
        -:   39: *          - <b>Wait</b>, a thread waits for the termination of another
        -:   40: *            thread and retrieves its return value.
        -:   41: *          - <b>Resume</b>, a thread created in suspended state is started.
        -:   42: *          - <b>Sleep</b>, the execution of a thread is suspended for the
        -:   43: *            specified amount of time or the specified future absolute time
        -:   44: *            is reached.
        -:   45: *          - <b>SetPriority</b>, a thread changes its own priority level.
        -:   46: *          - <b>Yield</b>, a thread voluntarily renounces to its time slot.
        -:   47: *          .
        -:   48: * @{
        -:   49: */
        -:   50:
        -:   51:#include "ch.h"
        -:   52:
        -:   53:/*===========================================================================*/
        -:   54:/* Module local definitions.                                                 */
        -:   55:/*===========================================================================*/
        -:   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 thread structure.
        -:   79: * @note    This is an internal functions, do not use it in application code.
        -:   80: *
        -:   81: * @param[in] tp        pointer to the thread
        -:   82: * @param[in] name      thread name
        -:   83: * @param[in] prio      the priority level for the new thread
        -:   84: * @return              The same thread pointer passed as parameter.
        -:   85: *
        -:   86: * @notapi
        -:   87: */
function _thread_init called 61931 returned 100% blocks executed 100%
    61931:   88:thread_t *_thread_init(thread_t *tp, const char *name, tprio_t prio) {
        -:   89:
    61931:   90:  tp->prio      = prio;
    61931:   91:  tp->state     = CH_STATE_WTSTART;
    61931:   92:  tp->flags     = CH_FLAG_MODE_STATIC;
        -:   93:#if CH_CFG_TIME_QUANTUM > 0
    61931:   94:  tp->preempt   = (tslices_t)CH_CFG_TIME_QUANTUM;
        -:   95:#endif
        -:   96:#if CH_CFG_USE_MUTEXES == TRUE
    61931:   97:  tp->realprio  = prio;
    61931:   98:  tp->mtxlist   = NULL;
        -:   99:#endif
        -:  100:#if CH_CFG_USE_EVENTS == TRUE
    61931:  101:  tp->epending  = (eventmask_t)0;
        -:  102:#endif
        -:  103:#if CH_DBG_THREADS_PROFILING == TRUE
    61931:  104:  tp->time      = (systime_t)0;
        -:  105:#endif
        -:  106:#if CH_CFG_USE_REGISTRY == TRUE
    61931:  107:  tp->refs      = (trefs_t)1;
    61931:  108:  tp->name      = name;
    61931:  109:  REG_INSERT(tp);
        -:  110:#else
        -:  111:  (void)name;
        -:  112:#endif
        -:  113:#if CH_CFG_USE_WAITEXIT == TRUE
    61931:  114:  list_init(&tp->waiting);
call    0 returned 100%
        -:  115:#endif
        -:  116:#if CH_CFG_USE_MESSAGES == TRUE
    61931:  117:  queue_init(&tp->msgqueue);
call    0 returned 100%
        -:  118:#endif
        -:  119:#if CH_DBG_STATISTICS == TRUE
        -:  120:  chTMObjectInit(&tp->stats);
        -:  121:#endif
        -:  122:  CH_CFG_THREAD_INIT_HOOK(tp);
    61931:  123:  return tp;
unconditional  0 taken 100%
        -:  124:}
        -:  125:
        -:  126:#if (CH_DBG_FILL_THREADS == TRUE) || defined(__DOXYGEN__)
        -:  127:/**
        -:  128: * @brief   Memory fill utility.
        -:  129: *
        -:  130: * @param[in] startp    first address to fill
        -:  131: * @param[in] endp      last address to fill +1
        -:  132: * @param[in] v         filler value
        -:  133: *
        -:  134: * @notapi
        -:  135: */
function _thread_memfill called 61930 returned 100% blocks executed 100%
    61930:  136:void _thread_memfill(uint8_t *startp, uint8_t *endp, uint8_t v) {
        -:  137:
1029648308:  138:  while (startp < endp) {
unconditional  0 taken 100%
branch  1 taken 99%
branch  2 taken 1% (fallthrough)
1029524448:  139:    *startp++ = v;
unconditional  0 taken 100%
        -:  140:  }
    61930:  141:}
        -:  142:#endif /* CH_DBG_FILL_THREADS */
        -:  143:
        -:  144:/**
        -:  145: * @brief   Creates a new thread into a static memory area.
        -:  146: * @details The new thread is initialized but not inserted in the ready list,
        -:  147: *          the initial state is @p CH_STATE_WTSTART.
        -:  148: * @post    The created thread has a reference counter set to one, it is
        -:  149: *          caller responsibility to call @p chThdRelease() or @p chthdWait()
        -:  150: *          in order to release the reference. The thread persists in the
        -:  151: *          registry until its reference counter reaches zero.
        -:  152: * @post    The initialized thread can be subsequently started by invoking
        -:  153: *          @p chThdStart(), @p chThdStartI() or @p chSchWakeupS()
        -:  154: *          depending on the execution context.
        -:  155: * @note    A thread can terminate by calling @p chThdExit() or by simply
        -:  156: *          returning from its main function.
        -:  157: * @note    Threads created using this function do not obey to the
        -:  158: *          @p CH_DBG_FILL_THREADS debug option because it would keep
        -:  159: *          the kernel locked for too much time.
        -:  160: *
        -:  161: * @param[out] tdp      pointer to the thread descriptor
        -:  162: * @return              The pointer to the @p thread_t structure allocated for
        -:  163: *                      the thread into the working space area.
        -:  164: *
        -:  165: * @iclass
        -:  166: */
function chThdCreateSuspendedI called 7 returned 100% blocks executed 80%
        7:  167:thread_t *chThdCreateSuspendedI(const thread_descriptor_t *tdp) {
        -:  168:  thread_t *tp;
        -:  169:
        7:  170:  chDbgCheckClassI();
call    0 returned 100%
        7:  171:  chDbgCheck(tdp != NULL);
branch  0 taken 0% (fallthrough)
branch  1 taken 100%
call    2 never executed
unconditional  3 never executed
unconditional  4 taken 100%
        7:  172:  chDbgCheck(MEM_IS_ALIGNED(tdp->wbase, PORT_WORKING_AREA_ALIGN) &&
branch  0 taken 100% (fallthrough)
branch  1 taken 0%
branch  2 taken 100% (fallthrough)
branch  3 taken 0%
branch  4 taken 100% (fallthrough)
branch  5 taken 0%
branch  6 taken 0% (fallthrough)
branch  7 taken 100%
call    8 never executed
unconditional  9 never executed
unconditional 10 taken 100%
        -:  173:             MEM_IS_ALIGNED(tdp->wend, PORT_STACK_ALIGN) &&
        -:  174:             (tdp->wend > tdp->wbase) &&
        -:  175:             (((size_t)tdp->wend - (size_t)tdp->wbase) >= THD_WORKING_AREA_SIZE(0)));
        7:  176:  chDbgCheck((tdp->prio <= HIGHPRIO) && (tdp->funcp != NULL));
branch  0 taken 100% (fallthrough)
branch  1 taken 0%
branch  2 taken 0% (fallthrough)
branch  3 taken 100%
call    4 never executed
unconditional  5 never executed
        -:  177:
        -:  178:  /* The thread structure is laid out in the upper part of the thread
        -:  179:     workspace. The thread position structure is aligned to the required
        -:  180:     stack alignment because it represents the stack top.*/
        7:  181:  tp = (thread_t *)((uint8_t *)tdp->wend -
        -:  182:                    MEM_ALIGN_NEXT(sizeof (thread_t), PORT_STACK_ALIGN));
        -:  183:
        -:  184:#if (CH_DBG_ENABLE_STACK_CHECK == TRUE) || (CH_CFG_USE_DYNAMIC == TRUE)
        -:  185:  /* Stack boundary.*/
        7:  186:  tp->wabase = tdp->wbase;
        -:  187:#endif
        -:  188:
        -:  189:  /* Setting up the port-dependent part of the working area.*/
        7:  190:  PORT_SETUP_CONTEXT(tp, tdp->wbase, tp, tdp->funcp, tdp->arg);
        -:  191:
        -:  192:  /* The driver object is initialized but not started.*/
        7:  193:  return _thread_init(tp, tdp->name, tdp->prio);
call    0 returned 100%
        -:  194:}
        -:  195:
        -:  196:/**
        -:  197: * @brief   Creates a new thread into a static memory area.
        -:  198: * @details The new thread is initialized but not inserted in the ready list,
        -:  199: *          the initial state is @p CH_STATE_WTSTART.
        -:  200: * @post    The created thread has a reference counter set to one, it is
        -:  201: *          caller responsibility to call @p chThdRelease() or @p chthdWait()
        -:  202: *          in order to release the reference. The thread persists in the
        -:  203: *          registry until its reference counter reaches zero.
        -:  204: * @post    The initialized thread can be subsequently started by invoking
        -:  205: *          @p chThdStart(), @p chThdStartI() or @p chSchWakeupS()
        -:  206: *          depending on the execution context.
        -:  207: * @note    A thread can terminate by calling @p chThdExit() or by simply
        -:  208: *          returning from its main function.
        -:  209: *
        -:  210: * @param[out] tdp      pointer to the thread descriptor
        -:  211: * @return              The pointer to the @p thread_t structure allocated for
        -:  212: *                      the thread into the working space area.
        -:  213: *
        -:  214: * @api
        -:  215: */
function chThdCreateSuspended called 0 returned 0% blocks executed 0%
    #####:  216:thread_t *chThdCreateSuspended(const thread_descriptor_t *tdp) {
unconditional  0 never executed
        -:  217:  thread_t *tp;
        -:  218:
        -:  219:#if CH_CFG_USE_REGISTRY == TRUE
    #####:  220:  chDbgAssert(chRegFindThreadByWorkingArea(tdp->wbase) == NULL,
call    0 never executed
branch  1 never executed
branch  2 never executed
call    3 never executed
unconditional  4 never executed
        -:  221:              "working area in use");
        -:  222:#endif
        -:  223:
        -:  224:#if CH_DBG_FILL_THREADS == TRUE
    #####:  225:  _thread_memfill((uint8_t *)tdp->wbase,
call    0 never executed
    #####:  226:                  (uint8_t *)tdp->wend,
        -:  227:                  CH_DBG_STACK_FILL_VALUE);
        -:  228:#endif
        -:  229:
    #####:  230:  chSysLock();
call    0 never executed
    #####:  231:  tp = chThdCreateSuspendedI(tdp);
call    0 never executed
    #####:  232:  chSysUnlock();
call    0 never executed
        -:  233:
    #####:  234:  return tp;
unconditional  0 never executed
        -:  235:}
        -:  236:
        -:  237:/**
        -:  238: * @brief   Creates a new thread into a static memory area.
        -:  239: * @details The new thread is initialized and make ready to execute.
        -:  240: * @post    The created thread has a reference counter set to one, it is
        -:  241: *          caller responsibility to call @p chThdRelease() or @p chthdWait()
        -:  242: *          in order to release the reference. The thread persists in the
        -:  243: *          registry until its reference counter reaches zero.
        -:  244: * @post    The initialized thread can be subsequently started by invoking
        -:  245: *          @p chThdStart(), @p chThdStartI() or @p chSchWakeupS()
        -:  246: *          depending on the execution context.
        -:  247: * @note    A thread can terminate by calling @p chThdExit() or by simply
        -:  248: *          returning from its main function.
        -:  249: * @note    Threads created using this function do not obey to the
        -:  250: *          @p CH_DBG_FILL_THREADS debug option because it would keep
        -:  251: *          the kernel locked for too much time.
        -:  252: *
        -:  253: * @param[out] tdp      pointer to the thread descriptor
        -:  254: * @return              The pointer to the @p thread_t structure allocated for
        -:  255: *                      the thread into the working space area.
        -:  256: *
        -:  257: * @iclass
        -:  258: */
function chThdCreateI called 0 returned 0% blocks executed 0%
    #####:  259:thread_t *chThdCreateI(const thread_descriptor_t *tdp) {
        -:  260:
    #####:  261:  return chSchReadyI(chThdCreateSuspendedI(tdp));
call    0 never executed
call    1 never executed
        -:  262:}
        -:  263:
        -:  264:/**
        -:  265: * @brief   Creates a new thread into a static memory area.
        -:  266: * @details The new thread is initialized and make ready to execute.
        -:  267: * @post    The created thread has a reference counter set to one, it is
        -:  268: *          caller responsibility to call @p chThdRelease() or @p chthdWait()
        -:  269: *          in order to release the reference. The thread persists in the
        -:  270: *          registry until its reference counter reaches zero.
        -:  271: * @note    A thread can terminate by calling @p chThdExit() or by simply
        -:  272: *          returning from its main function.
        -:  273: *
        -:  274: * @param[out] tdp      pointer to the thread descriptor
        -:  275: * @return              The pointer to the @p thread_t structure allocated for
        -:  276: *                      the thread into the working space area.
        -:  277: *
        -:  278: * @iclass
        -:  279: */
function chThdCreate called 1 returned 100% blocks executed 91%
        1:  280:thread_t *chThdCreate(const thread_descriptor_t *tdp) {
unconditional  0 taken 100%
        -:  281:  thread_t *tp;
        -:  282:
        -:  283:#if CH_CFG_USE_REGISTRY == TRUE
        1:  284:  chDbgAssert(chRegFindThreadByWorkingArea(tdp->wbase) == NULL,
call    0 returned 100%
branch  1 taken 0% (fallthrough)
branch  2 taken 100%
call    3 never executed
unconditional  4 never executed
        -:  285:              "working area in use");
        -:  286:#endif
        -:  287:
        -:  288:#if CH_DBG_FILL_THREADS == TRUE
        1:  289:  _thread_memfill((uint8_t *)tdp->wbase,
call    0 returned 100%
        1:  290:                  (uint8_t *)tdp->wend,
        -:  291:                  CH_DBG_STACK_FILL_VALUE);
        -:  292:#endif
        -:  293:
        1:  294:  chSysLock();
call    0 returned 100%
        1:  295:  tp = chThdCreateSuspendedI(tdp);
call    0 returned 100%
        1:  296:  chSchWakeupS(tp, MSG_OK);
call    0 returned 100%
        1:  297:  chSysUnlock();
call    0 returned 100%
        -:  298:
        1:  299:  return tp;
unconditional  0 taken 100%
        -:  300:}
        -:  301:
        -:  302:/**
        -:  303: * @brief   Creates a new thread into a static memory area.
        -:  304: * @post    The created thread has a reference counter set to one, it is
        -:  305: *          caller responsibility to call @p chThdRelease() or @p chthdWait()
        -:  306: *          in order to release the reference. The thread persists in the
        -:  307: *          registry until its reference counter reaches zero.
        -:  308: * @note    A thread can terminate by calling @p chThdExit() or by simply
        -:  309: *          returning from its main function.
        -:  310: *
        -:  311: * @param[out] wsp      pointer to a working area dedicated to the thread stack
        -:  312: * @param[in] size      size of the working area
        -:  313: * @param[in] prio      the priority level for the new thread
        -:  314: * @param[in] pf        the thread function
        -:  315: * @param[in] arg       an argument passed to the thread function. It can be
        -:  316: *                      @p NULL.
        -:  317: * @return              The pointer to the @p thread_t structure allocated for
        -:  318: *                      the thread into the working space area.
        -:  319: *
        -:  320: * @api
        -:  321: */
function chThdCreateStatic called 61923 returned 100% blocks executed 89%
    61923:  322:thread_t *chThdCreateStatic(void *wsp, size_t size,
unconditional  0 taken 100%
        -:  323:                            tprio_t prio, tfunc_t pf, void *arg) {
        -:  324:  thread_t *tp;
        -:  325:
    61923:  326:  chDbgCheck((wsp != NULL) &&
branch  0 taken 100% (fallthrough)
branch  1 taken 0%
branch  2 taken 100% (fallthrough)
branch  3 taken 0%
branch  4 taken 100% (fallthrough)
branch  5 taken 0%
branch  6 taken 100% (fallthrough)
branch  7 taken 0%
branch  8 taken 100% (fallthrough)
branch  9 taken 0%
branch 10 taken 0% (fallthrough)
branch 11 taken 100%
call   12 never executed
unconditional 13 never executed
unconditional 14 taken 100%
        -:  327:             MEM_IS_ALIGNED(wsp, PORT_WORKING_AREA_ALIGN) &&
        -:  328:             (size >= THD_WORKING_AREA_SIZE(0)) &&
        -:  329:             MEM_IS_ALIGNED(size, PORT_STACK_ALIGN) &&
        -:  330:             (prio <= HIGHPRIO) && (pf != NULL));
        -:  331:
        -:  332:#if CH_CFG_USE_REGISTRY == TRUE
    61923:  333:  chDbgAssert(chRegFindThreadByWorkingArea(wsp) == NULL,
call    0 returned 100%
branch  1 taken 0% (fallthrough)
branch  2 taken 100%
call    3 never executed
unconditional  4 never executed
        -:  334:              "working area in use");
        -:  335:#endif
        -:  336:
        -:  337:#if CH_DBG_FILL_THREADS == TRUE
    61923:  338:  _thread_memfill((uint8_t *)wsp,
call    0 returned 100%
        -:  339:                  (uint8_t *)wsp + size,
        -:  340:                  CH_DBG_STACK_FILL_VALUE);
        -:  341:#endif
        -:  342:
    61923:  343:  chSysLock();
call    0 returned 100%
        -:  344:
        -:  345:  /* The thread structure is laid out in the upper part of the thread
        -:  346:     workspace. The thread position structure is aligned to the required
        -:  347:     stack alignment because it represents the stack top.*/
    61923:  348:  tp = (thread_t *)((uint8_t *)wsp + size -
        -:  349:                    MEM_ALIGN_NEXT(sizeof (thread_t), PORT_STACK_ALIGN));
        -:  350:
        -:  351:#if (CH_DBG_ENABLE_STACK_CHECK == TRUE) || (CH_CFG_USE_DYNAMIC == TRUE)
        -:  352:  /* Stack boundary.*/
    61923:  353:  tp->wabase = (stkalign_t *)wsp;
        -:  354:#endif
        -:  355:
        -:  356:  /* Setting up the port-dependent part of the working area.*/
    61923:  357:  PORT_SETUP_CONTEXT(tp, wsp, tp, pf, arg);
        -:  358:
    61923:  359:  tp = _thread_init(tp, "noname", prio);
call    0 returned 100%
        -:  360:
        -:  361:  /* Starting the thread immediately.*/
    61923:  362:  chSchWakeupS(tp, MSG_OK);
call    0 returned 100%
    61923:  363:  chSysUnlock();
call    0 returned 100%
        -:  364:
    61923:  365:  return tp;
unconditional  0 taken 100%
        -:  366:}
        -:  367:
        -:  368:/**
        -:  369: * @brief   Resumes a thread created with @p chThdCreateI().
        -:  370: *
        -:  371: * @param[in] tp        pointer to the thread
        -:  372: * @return              The pointer to the @p thread_t structure allocated for
        -:  373: *                      the thread into the working space area.
        -:  374: *
        -:  375: * @api
        -:  376: */
function chThdStart called 0 returned 0% blocks executed 0%
    #####:  377:thread_t *chThdStart(thread_t *tp) {
        -:  378:
    #####:  379:  chSysLock();
call    0 never executed
    #####:  380:  chDbgAssert(tp->state == CH_STATE_WTSTART, "wrong state");
branch  0 never executed
branch  1 never executed
call    2 never executed
unconditional  3 never executed
    #####:  381:  chSchWakeupS(tp, MSG_OK);
call    0 never executed
    #####:  382:  chSysUnlock();
call    0 never executed
        -:  383:
    #####:  384:  return tp;
unconditional  0 never executed
        -:  385:}
        -:  386:
        -:  387:#if (CH_CFG_USE_REGISTRY == TRUE) || defined(__DOXYGEN__)
        -:  388:/**
        -:  389: * @brief   Adds a reference to a thread object.
        -:  390: * @pre     The configuration option @p CH_CFG_USE_DYNAMIC must be enabled in
        -:  391: *          order to use this function.
        -:  392: *
        -:  393: * @param[in] tp        pointer to the thread
        -:  394: * @return              The same thread pointer passed as parameter
        -:  395: *                      representing the new reference.
        -:  396: *
        -:  397: * @api
        -:  398: */
function chThdAddRef called 0 returned 0% blocks executed 0%
    #####:  399:thread_t *chThdAddRef(thread_t *tp) {
        -:  400:
    #####:  401:  chSysLock();
call    0 never executed
    #####:  402:  chDbgAssert(tp->refs < (trefs_t)255, "too many references");
branch  0 never executed
branch  1 never executed
call    2 never executed
unconditional  3 never executed
    #####:  403:  tp->refs++;
    #####:  404:  chSysUnlock();
call    0 never executed
        -:  405:
    #####:  406:  return tp;
unconditional  0 never executed
        -:  407:}
        -:  408:
        -:  409:/**
        -:  410: * @brief   Releases a reference to a thread object.
        -:  411: * @details If the references counter reaches zero <b>and</b> the thread
        -:  412: *          is in the @p CH_STATE_FINAL state then the thread's memory is
        -:  413: *          returned to the proper allocator and the thread is removed
        -:  414: *          from the registry.<br>
        -:  415: *          Threads whose counter reaches zero and are still active become
        -:  416: *          "detached" and will be removed from registry on termination.
        -:  417: * @pre     The configuration option @p CH_CFG_USE_DYNAMIC must be enabled in
        -:  418: *          order to use this function.
        -:  419: * @note    Static threads are not affected.
        -:  420: *
        -:  421: * @param[in] tp        pointer to the thread
        -:  422: *
        -:  423: * @api
        -:  424: */
function chThdRelease called 185893 returned 100% blocks executed 94%
   185893:  425:void chThdRelease(thread_t *tp) {
        -:  426:
   185893:  427:  chSysLock();
call    0 returned 100%
   185893:  428:  chDbgAssert(tp->refs > (trefs_t)0, "not referenced");
branch  0 taken 0% (fallthrough)
branch  1 taken 100%
call    2 never executed
unconditional  3 never executed
   185893:  429:  tp->refs--;
        -:  430:
        -:  431:  /* If the references counter reaches zero and the thread is in its
        -:  432:     terminated state then the memory can be returned to the proper
        -:  433:     allocator.*/
   185893:  434:  if ((tp->refs == (trefs_t)0) && (tp->state == CH_STATE_FINAL)) {
branch  0 taken 33% (fallthrough)
branch  1 taken 67%
branch  2 taken 100% (fallthrough)
branch  3 taken 0%
    61929:  435:    REG_REMOVE(tp);
    61929:  436:    chSysUnlock();
call    0 returned 100%
        -:  437:
        -:  438:#if CH_CFG_USE_DYNAMIC == TRUE
    61929:  439:    switch (tp->flags & CH_FLAG_MODE_MASK) {
branch  0 taken 1%
branch  1 taken 1%
branch  2 taken 99%
        -:  440:#if CH_CFG_USE_HEAP == TRUE
        -:  441:    case CH_FLAG_MODE_HEAP:
        2:  442:      chHeapFree(chThdGetWorkingAreaX(tp));
call    0 returned 100%
call    1 returned 100%
        2:  443:      break;
unconditional  0 taken 100%
        -:  444:#endif
        -:  445:#if CH_CFG_USE_MEMPOOLS == TRUE
        -:  446:    case CH_FLAG_MODE_MPOOL:
        4:  447:      chPoolFree(tp->mpool, chThdGetWorkingAreaX(tp));
call    0 returned 100%
call    1 returned 100%
        4:  448:      break;
unconditional  0 taken 100%
        -:  449:#endif
        -:  450:    default:
        -:  451:      /* Nothing else to do for static threads.*/
    61923:  452:      break;
unconditional  0 taken 100%
        -:  453:    }
        -:  454:#endif /* CH_CFG_USE_DYNAMIC == TRUE */
    61929:  455:    return;
unconditional  0 taken 100%
        -:  456:  }
   123964:  457:  chSysUnlock();
call    0 returned 100%
unconditional  1 taken 100%
        -:  458:}
        -:  459:#endif /* CH_CFG_USE_REGISTRY == TRUE */
        -:  460:
        -:  461:/**
        -:  462: * @brief   Terminates the current thread.
        -:  463: * @details The thread goes in the @p CH_STATE_FINAL state holding the
        -:  464: *          specified exit status code, other threads can retrieve the
        -:  465: *          exit status code by invoking the function @p chThdWait().
        -:  466: * @post    Eventual code after this function will never be executed,
        -:  467: *          this function never returns. The compiler has no way to
        -:  468: *          know this so do not assume that the compiler would remove
        -:  469: *          the dead code.
        -:  470: *
        -:  471: * @param[in] msg       thread exit code
        -:  472: *
        -:  473: * @api
        -:  474: */
function chThdExit called 61929 returned 0% blocks executed 100%
    61929:  475:void chThdExit(msg_t msg) {
        -:  476:
    61929:  477:  chSysLock();
call    0 returned 100%
    61929:  478:  chThdExitS(msg);
call    0 returned 0%
        -:  479:  /* The thread never returns here.*/
    #####:  480:}
        -:  481:
        -:  482:/**
        -:  483: * @brief   Terminates the current thread.
        -:  484: * @details The thread goes in the @p CH_STATE_FINAL state holding the
        -:  485: *          specified exit status code, other threads can retrieve the
        -:  486: *          exit status code by invoking the function @p chThdWait().
        -:  487: * @post    Exiting a non-static thread that does not have references
        -:  488: *          (detached) causes the thread to remain in the registry.
        -:  489: *          It can only be removed by performing a registry scan operation.
        -:  490: * @post    Eventual code after this function will never be executed,
        -:  491: *          this function never returns. The compiler has no way to
        -:  492: *          know this so do not assume that the compiler would remove
        -:  493: *          the dead code.
        -:  494: *
        -:  495: * @param[in] msg       thread exit code
        -:  496: *
        -:  497: * @sclass
        -:  498: */
function chThdExitS called 61929 returned 0% blocks executed 73%
    61929:  499:void chThdExitS(msg_t msg) {
    61929:  500:  thread_t *tp = currp;
        -:  501:
        -:  502:  /* Storing exit message.*/
    61929:  503:  tp->u.exitcode = msg;
        -:  504:
        -:  505:  /* Exit handler hook.*/
        -:  506:  CH_CFG_THREAD_EXIT_HOOK(tp);
        -:  507:
        -:  508:#if CH_CFG_USE_WAITEXIT == TRUE
        -:  509:  /* Waking up any waiting thread.*/
   154789:  510:  while (list_notempty(&tp->waiting)) {
unconditional  0 taken 100%
call    1 returned 100%
branch  2 taken 33%
branch  3 taken 67% (fallthrough)
    30931:  511:    (void) chSchReadyI(list_remove(&tp->waiting));
call    0 returned 100%
call    1 returned 100%
unconditional  2 taken 100%
        -:  512:  }
        -:  513:#endif
        -:  514:
        -:  515:#if CH_CFG_USE_REGISTRY == TRUE
        -:  516:  /* Static threads with no references are immediately removed from the
        -:  517:     registry because there is no memory to recover.*/
        -:  518:#if CH_CFG_USE_DYNAMIC == TRUE
    61929:  519:  if ((tp->refs == (trefs_t)0) &&
branch  0 taken 0% (fallthrough)
branch  1 taken 100%
branch  2 never executed
branch  3 never executed
    #####:  520:      ((tp->flags & CH_FLAG_MODE_MASK) == CH_FLAG_MODE_STATIC)) {
    #####:  521:    REG_REMOVE(tp);
unconditional  0 never executed
        -:  522:  }
        -:  523:#else
        -:  524:  if (tp->refs == (trefs_t)0) {
        -:  525:    REG_REMOVE(tp);
        -:  526:  }
        -:  527:#endif
        -:  528:#endif
        -:  529:
        -:  530:  /* Going into final state.*/
    61929:  531:  chSchGoSleepS(CH_STATE_FINAL);
call    0 returned 0%
        -:  532:
        -:  533:  /* The thread never returns here.*/
    #####:  534:  chDbgAssert(false, "zombies apocalypse");
call    0 never executed
    #####:  535:}
        -:  536:
        -:  537:#if (CH_CFG_USE_WAITEXIT == TRUE) || defined(__DOXYGEN__)
        -:  538:/**
        -:  539: * @brief   Blocks the execution of the invoking thread until the specified
        -:  540: *          thread terminates then the exit code is returned.
        -:  541: * @details This function waits for the specified thread to terminate then
        -:  542: *          decrements its reference counter, if the counter reaches zero then
        -:  543: *          the thread working area is returned to the proper allocator and
        -:  544: *          the thread is removed from registry.
        -:  545: * @pre     The configuration option @p CH_CFG_USE_WAITEXIT must be enabled in
        -:  546: *          order to use this function.
        -:  547: * @post    Enabling @p chThdWait() requires 2-4 (depending on the
        -:  548: *          architecture) extra bytes in the @p thread_t structure.
        -:  549: * @note    If @p CH_CFG_USE_DYNAMIC is not specified this function just waits
        -:  550: *          for the thread termination, no memory allocators are involved.
        -:  551: *
        -:  552: * @param[in] tp        pointer to the thread
        -:  553: * @return              The exit code from the terminated thread.
        -:  554: *
        -:  555: * @api
        -:  556: */
function chThdWait called 30987 returned 100% blocks executed 81%
    30987:  557:msg_t chThdWait(thread_t *tp) {
unconditional  0 taken 100%
        -:  558:  msg_t msg;
        -:  559:
    30987:  560:  chDbgCheck(tp != NULL);
branch  0 taken 0% (fallthrough)
branch  1 taken 100%
call    2 never executed
unconditional  3 never executed
        -:  561:
    30987:  562:  chSysLock();
call    0 returned 100%
    30987:  563:  chDbgAssert(tp != currp, "waiting self");
branch  0 taken 0% (fallthrough)
branch  1 taken 100%
call    2 never executed
unconditional  3 never executed
unconditional  4 taken 100%
        -:  564:#if CH_CFG_USE_REGISTRY == TRUE
    30987:  565:  chDbgAssert(tp->refs > (trefs_t)0, "no references");
branch  0 taken 0% (fallthrough)
branch  1 taken 100%
call    2 never executed
unconditional  3 never executed
        -:  566:#endif
        -:  567:
    30987:  568:  if (tp->state != CH_STATE_FINAL) {
branch  0 taken 99% (fallthrough)
branch  1 taken 1%
    30931:  569:    list_insert(currp, &tp->waiting);
call    0 returned 100%
    30931:  570:    chSchGoSleepS(CH_STATE_WTEXIT);
call    0 returned 100%
unconditional  1 taken 100%
        -:  571:  }
    30987:  572:  msg = tp->u.exitcode;
    30987:  573:  chSysUnlock();
call    0 returned 100%
        -:  574:
        -:  575:#if CH_CFG_USE_REGISTRY == TRUE
        -:  576:  /* Releasing a reference to the thread.*/
    30987:  577:  chThdRelease(tp);
call    0 returned 100%
        -:  578:#endif
        -:  579:
    30987:  580:  return msg;
unconditional  0 taken 100%
        -:  581:}
        -:  582:#endif /* CH_CFG_USE_WAITEXIT */
        -:  583:
        -:  584:/**
        -:  585: * @brief   Changes the running thread priority level then reschedules if
        -:  586: *          necessary.
        -:  587: * @note    The function returns the real thread priority regardless of the
        -:  588: *          current priority that could be higher than the real priority
        -:  589: *          because the priority inheritance mechanism.
        -:  590: *
        -:  591: * @param[in] newprio   the new priority level of the running thread
        -:  592: * @return              The old priority level.
        -:  593: *
        -:  594: * @api
        -:  595: */
function chThdSetPriority called 4 returned 100% blocks executed 91%
        4:  596:tprio_t chThdSetPriority(tprio_t newprio) {
unconditional  0 taken 100%
        -:  597:  tprio_t oldprio;
        -:  598:
        4:  599:  chDbgCheck(newprio <= HIGHPRIO);
branch  0 taken 0% (fallthrough)
branch  1 taken 100%
call    2 never executed
unconditional  3 never executed
        -:  600:
        4:  601:  chSysLock();
call    0 returned 100%
        -:  602:#if CH_CFG_USE_MUTEXES == TRUE
        4:  603:  oldprio = currp->realprio;
        4:  604:  if ((currp->prio == currp->realprio) || (newprio > currp->prio)) {
branch  0 taken 50% (fallthrough)
branch  1 taken 50%
branch  2 taken 50% (fallthrough)
branch  3 taken 50%
        3:  605:    currp->prio = newprio;
unconditional  0 taken 100%
        -:  606:  }
        4:  607:  currp->realprio = newprio;
        -:  608:#else
        -:  609:  oldprio = currp->prio;
        -:  610:  currp->prio = newprio;
        -:  611:#endif
        4:  612:  chSchRescheduleS();
call    0 returned 100%
        4:  613:  chSysUnlock();
call    0 returned 100%
        -:  614:
        4:  615:  return oldprio;
unconditional  0 taken 100%
        -:  616:}
        -:  617:
        -:  618:/**
        -:  619: * @brief   Requests a thread termination.
        -:  620: * @pre     The target thread must be written to invoke periodically
        -:  621: *          @p chThdShouldTerminate() and terminate cleanly if it returns
        -:  622: *          @p true.
        -:  623: * @post    The specified thread will terminate after detecting the termination
        -:  624: *          condition.
        -:  625: *
        -:  626: * @param[in] tp        pointer to the thread
        -:  627: *
        -:  628: * @api
        -:  629: */
function chThdTerminate called 10 returned 100% blocks executed 100%
       10:  630:void chThdTerminate(thread_t *tp) {
        -:  631:
       10:  632:  chSysLock();
call    0 returned 100%
       10:  633:  tp->flags |= CH_FLAG_TERMINATE;
       10:  634:  chSysUnlock();
call    0 returned 100%
       10:  635:}
        -:  636:
        -:  637:/**
        -:  638: * @brief   Suspends the invoking thread for the specified time.
        -:  639: *
        -:  640: * @param[in] time      the delay in system ticks, the special values are
        -:  641: *                      handled as follow:
        -:  642: *                      - @a TIME_INFINITE the thread enters an infinite sleep
        -:  643: *                        state.
        -:  644: *                      - @a TIME_IMMEDIATE this value is not allowed.
        -:  645: *                      .
        -:  646: *
        -:  647: * @api
        -:  648: */
function chThdSleep called 39 returned 100% blocks executed 100%
       39:  649:void chThdSleep(systime_t time) {
        -:  650:
       39:  651:  chSysLock();
call    0 returned 100%
       39:  652:  chThdSleepS(time);
call    0 returned 100%
       39:  653:  chSysUnlock();
call    0 returned 100%
       39:  654:}
        -:  655:
        -:  656:/**
        -:  657: * @brief   Suspends the invoking thread until the system time arrives to the
        -:  658: *          specified value.
        -:  659: * @note    The function has no concept of "past", all specifiable times
        -:  660: *          are in the future, this means that if you call this function
        -:  661: *          exceeding your calculated intervals then the function will
        -:  662: *          return in a far future time, not immediately.
        -:  663: * @see     chThdSleepUntilWindowed()
        -:  664: *
        -:  665: * @param[in] time      absolute system time
        -:  666: *
        -:  667: * @api
        -:  668: */
function chThdSleepUntil called 1 returned 100% blocks executed 100%
        1:  669:void chThdSleepUntil(systime_t time) {
        -:  670:
        1:  671:  chSysLock();
call    0 returned 100%
        1:  672:  time -= chVTGetSystemTimeX();
call    0 returned 100%
        1:  673:  if (time > (systime_t)0) {
branch  0 taken 100% (fallthrough)
branch  1 taken 0%
        1:  674:    chThdSleepS(time);
call    0 returned 100%
unconditional  1 taken 100%
        -:  675:  }
        1:  676:  chSysUnlock();
call    0 returned 100%
        1:  677:}
        -:  678:
        -:  679:/**
        -:  680: * @brief   Suspends the invoking thread until the system time arrives to the
        -:  681: *          specified value.
        -:  682: * @note    The system time is assumed to be between @p prev and @p time
        -:  683: *          else the call is assumed to have been called outside the
        -:  684: *          allowed time interval, in this case no sleep is performed.
        -:  685: * @see     chThdSleepUntil()
        -:  686: *
        -:  687: * @param[in] prev      absolute system time of the previous deadline
        -:  688: * @param[in] next      absolute system time of the next deadline
        -:  689: * @return              the @p next parameter
        -:  690: *
        -:  691: * @api
        -:  692: */
function chThdSleepUntilWindowed called 0 returned 0% blocks executed 0%
    #####:  693:systime_t chThdSleepUntilWindowed(systime_t prev, systime_t next) {
        -:  694:  systime_t time;
        -:  695:
    #####:  696:  chSysLock();
call    0 never executed
    #####:  697:  time = chVTGetSystemTimeX();
call    0 never executed
    #####:  698:  if (chVTIsTimeWithinX(time, prev, next)) {
call    0 never executed
branch  1 never executed
branch  2 never executed
    #####:  699:    chThdSleepS(next - time);
call    0 never executed
unconditional  1 never executed
        -:  700:  }
    #####:  701:  chSysUnlock();
call    0 never executed
        -:  702:
    #####:  703:  return next;
unconditional  0 never executed
        -:  704:}
        -:  705:
        -:  706:/**
        -:  707: * @brief   Yields the time slot.
        -:  708: * @details Yields the CPU control to the next thread in the ready list with
        -:  709: *          equal priority, if any.
        -:  710: *
        -:  711: * @api
        -:  712: */
function chThdYield called 15959820 returned 100% blocks executed 100%
 15959820:  713:void chThdYield(void) {
        -:  714:
 15959820:  715:  chSysLock();
call    0 returned 100%
 15959820:  716:  chSchDoYieldS();
call    0 returned 100%
 15959820:  717:  chSysUnlock();
call    0 returned 100%
 15959820:  718:}
        -:  719:
        -:  720:/**
        -:  721: * @brief   Sends the current thread sleeping and sets a reference variable.
        -:  722: * @note    This function must reschedule, it can only be called from thread
        -:  723: *          context.
        -:  724: *
        -:  725: * @param[in] trp       a pointer to a thread reference object
        -:  726: * @return              The wake up message.
        -:  727: *
        -:  728: * @sclass
        -:  729: */
function chThdSuspendS called 0 returned 0% blocks executed 0%
    #####:  730:msg_t chThdSuspendS(thread_reference_t *trp) {
    #####:  731:  thread_t *tp = chThdGetSelfX();
call    0 never executed
        -:  732:
    #####:  733:  chDbgAssert(*trp == NULL, "not NULL");
branch  0 never executed
branch  1 never executed
call    2 never executed
unconditional  3 never executed
        -:  734:
    #####:  735:  *trp = tp;
    #####:  736:  tp->u.wttrp = trp;
    #####:  737:  chSchGoSleepS(CH_STATE_SUSPENDED);
call    0 never executed
        -:  738:
    #####:  739:  return chThdGetSelfX()->u.rdymsg;
call    0 never executed
unconditional  1 never executed
        -:  740:}
        -:  741:
        -:  742:/**
        -:  743: * @brief   Sends the current thread sleeping and sets a reference variable.
        -:  744: * @note    This function must reschedule, it can only be called from thread
        -:  745: *          context.
        -:  746: *
        -:  747: * @param[in] trp       a pointer to a thread reference object
        -:  748: * @param[in] timeout   the timeout in system ticks, the special values are
        -:  749: *                      handled as follow:
        -:  750: *                      - @a TIME_INFINITE the thread enters an infinite sleep
        -:  751: *                        state.
        -:  752: *                      - @a TIME_IMMEDIATE the thread is not enqueued and
        -:  753: *                        the function returns @p MSG_TIMEOUT as if a timeout
        -:  754: *                        occurred.
        -:  755: *                      .
        -:  756: * @return              The wake up message.
        -:  757: * @retval MSG_TIMEOUT  if the operation timed out.
        -:  758: *
        -:  759: * @sclass
        -:  760: */
function chThdSuspendTimeoutS called 2 returned 100% blocks executed 71%
        2:  761:msg_t chThdSuspendTimeoutS(thread_reference_t *trp, systime_t timeout) {
        2:  762:  thread_t *tp = chThdGetSelfX();
call    0 returned 100%
        -:  763:
        2:  764:  chDbgAssert(*trp == NULL, "not NULL");
branch  0 taken 0% (fallthrough)
branch  1 taken 100%
call    2 never executed
unconditional  3 never executed
        -:  765:
        2:  766:  if (TIME_IMMEDIATE == timeout) {
branch  0 taken 0% (fallthrough)
branch  1 taken 100%
    #####:  767:    return MSG_TIMEOUT;
unconditional  0 never executed
        -:  768:  }
        -:  769:
        2:  770:  *trp = tp;
        2:  771:  tp->u.wttrp = trp;
        -:  772:
        2:  773:  return chSchGoSleepTimeoutS(CH_STATE_SUSPENDED, timeout);
call    0 returned 100%
unconditional  1 taken 100%
        -:  774:}
        -:  775:
        -:  776:/**
        -:  777: * @brief   Wakes up a thread waiting on a thread reference object.
        -:  778: * @note    This function must not reschedule because it can be called from
        -:  779: *          ISR context.
        -:  780: *
        -:  781: * @param[in] trp       a pointer to a thread reference object
        -:  782: * @param[in] msg       the message code
        -:  783: *
        -:  784: * @iclass
        -:  785: */
function chThdResumeI called 1 returned 100% blocks executed 83%
        1:  786:void chThdResumeI(thread_reference_t *trp, msg_t msg) {
        -:  787:
        1:  788:  if (*trp != NULL) {
branch  0 taken 100% (fallthrough)
branch  1 taken 0%
        1:  789:    thread_t *tp = *trp;
unconditional  0 taken 100%
        -:  790:
        1:  791:    chDbgAssert(tp->state == CH_STATE_SUSPENDED, "not CH_STATE_SUSPENDED");
branch  0 taken 0% (fallthrough)
branch  1 taken 100%
call    2 never executed
unconditional  3 never executed
        -:  792:
        1:  793:    *trp = NULL;
        1:  794:    tp->u.rdymsg = msg;
        1:  795:    (void) chSchReadyI(tp);
call    0 returned 100%
unconditional  1 taken 100%
        -:  796:  }
        1:  797:}
        -:  798:
        -:  799:/**
        -:  800: * @brief   Wakes up a thread waiting on a thread reference object.
        -:  801: * @note    This function must reschedule, it can only be called from thread
        -:  802: *          context.
        -:  803: *
        -:  804: * @param[in] trp       a pointer to a thread reference object
        -:  805: * @param[in] msg       the message code
        -:  806: *
        -:  807: * @iclass
        -:  808: */
function chThdResumeS called 0 returned 0% blocks executed 0%
    #####:  809:void chThdResumeS(thread_reference_t *trp, msg_t msg) {
        -:  810:
    #####:  811:  if (*trp != NULL) {
branch  0 never executed
branch  1 never executed
    #####:  812:    thread_t *tp = *trp;
unconditional  0 never executed
        -:  813:
    #####:  814:    chDbgAssert(tp->state == CH_STATE_SUSPENDED, "not CH_STATE_SUSPENDED");
branch  0 never executed
branch  1 never executed
call    2 never executed
unconditional  3 never executed
        -:  815:
    #####:  816:    *trp = NULL;
    #####:  817:    chSchWakeupS(tp, msg);
call    0 never executed
unconditional  1 never executed
        -:  818:  }
    #####:  819:}
        -:  820:
        -:  821:/**
        -:  822: * @brief   Wakes up a thread waiting on a thread reference object.
        -:  823: * @note    This function must reschedule, it can only be called from thread
        -:  824: *          context.
        -:  825: *
        -:  826: * @param[in] trp       a pointer to a thread reference object
        -:  827: * @param[in] msg       the message code
        -:  828: *
        -:  829: * @api
        -:  830: */
function chThdResume called 0 returned 0% blocks executed 0%
    #####:  831:void chThdResume(thread_reference_t *trp, msg_t msg) {
        -:  832:
    #####:  833:  chSysLock();
call    0 never executed
    #####:  834:  chThdResumeS(trp, msg);
call    0 never executed
    #####:  835:  chSysUnlock();
call    0 never executed
    #####:  836:}
        -:  837:
        -:  838:/**
        -:  839: * @brief   Enqueues the caller thread on a threads queue object.
        -:  840: * @details The caller thread is enqueued and put to sleep until it is
        -:  841: *          dequeued or the specified timeouts expires.
        -:  842: *
        -:  843: * @param[in] tqp       pointer to the threads queue object
        -:  844: * @param[in] timeout   the timeout in system ticks, the special values are
        -:  845: *                      handled as follow:
        -:  846: *                      - @a TIME_INFINITE the thread enters an infinite sleep
        -:  847: *                        state.
        -:  848: *                      - @a TIME_IMMEDIATE the thread is not enqueued and
        -:  849: *                        the function returns @p MSG_TIMEOUT as if a timeout
        -:  850: *                        occurred.
        -:  851: *                      .
        -:  852: * @return              The message from @p osalQueueWakeupOneI() or
        -:  853: *                      @p osalQueueWakeupAllI() functions.
        -:  854: * @retval MSG_TIMEOUT  if the thread has not been dequeued within the
        -:  855: *                      specified timeout or if the function has been
        -:  856: *                      invoked with @p TIME_IMMEDIATE as timeout
        -:  857: *                      specification.
        -:  858: *
        -:  859: * @sclass
        -:  860: */
function chThdEnqueueTimeoutS called 3 returned 100% blocks executed 80%
        3:  861:msg_t chThdEnqueueTimeoutS(threads_queue_t *tqp, systime_t timeout) {
        -:  862:
        3:  863:  if (TIME_IMMEDIATE == timeout) {
branch  0 taken 0% (fallthrough)
branch  1 taken 100%
    #####:  864:    return MSG_TIMEOUT;
unconditional  0 never executed
        -:  865:  }
        -:  866:
        3:  867:  queue_insert(currp, tqp);
call    0 returned 100%
        -:  868:
        3:  869:  return chSchGoSleepTimeoutS(CH_STATE_QUEUED, timeout);
call    0 returned 100%
unconditional  1 taken 100%
        -:  870:}
        -:  871:
        -:  872:/**
        -:  873: * @brief   Dequeues and wakes up one thread from the threads queue object,
        -:  874: *          if any.
        -:  875: *
        -:  876: * @param[in] tqp       pointer to the threads queue object
        -:  877: * @param[in] msg       the message code
        -:  878: *
        -:  879: * @iclass
        -:  880: */
function chThdDequeueNextI called 24 returned 100% blocks executed 75%
       24:  881:void chThdDequeueNextI(threads_queue_t *tqp, msg_t msg) {
        -:  882:
       24:  883:  if (queue_notempty(tqp)) {
call    0 returned 100%
branch  1 taken 0% (fallthrough)
branch  2 taken 100%
    #####:  884:    chThdDoDequeueNextI(tqp, msg);
call    0 never executed
unconditional  1 never executed
        -:  885:  }
       24:  886:}
        -:  887:
        -:  888:/**
        -:  889: * @brief   Dequeues and wakes up all threads from the threads queue object.
        -:  890: *
        -:  891: * @param[in] tqp       pointer to the threads queue object
        -:  892: * @param[in] msg       the message code
        -:  893: *
        -:  894: * @iclass
        -:  895: */
function chThdDequeueAllI called 12 returned 100% blocks executed 80%
       12:  896:void chThdDequeueAllI(threads_queue_t *tqp, msg_t msg) {
        -:  897:
       24:  898:  while (queue_notempty(tqp)) {
unconditional  0 taken 100%
call    1 returned 100%
branch  2 taken 0%
branch  3 taken 100% (fallthrough)
    #####:  899:    chThdDoDequeueNextI(tqp, msg);
call    0 never executed
unconditional  1 never executed
        -:  900:  }
       12:  901:}
        -:  902:
        -:  903:/** @} */
