        -:    0:Source:../../../os/rt/src/chschd.c
        -:    0:Programs:16
        -:    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    chschd.c
        -:   22: * @brief   Scheduler code.
        -:   23: *
        -:   24: * @addtogroup scheduler
        -:   25: * @details This module provides the default portable scheduler code.
        -:   26: * @{
        -:   27: */
        -:   28:
        -:   29:#include "ch.h"
        -:   30:
        -:   31:/*===========================================================================*/
        -:   32:/* Module local definitions.                                                 */
        -:   33:/*===========================================================================*/
        -:   34:
        -:   35:/*===========================================================================*/
        -:   36:/* Module exported variables.                                                */
        -:   37:/*===========================================================================*/
        -:   38:
        -:   39:/**
        -:   40: * @brief   System data structures.
        -:   41: */
        -:   42:ch_system_t ch;
        -:   43:
        -:   44:/*===========================================================================*/
        -:   45:/* Module local types.                                                       */
        -:   46:/*===========================================================================*/
        -:   47:
        -:   48:/*===========================================================================*/
        -:   49:/* Module local variables.                                                   */
        -:   50:/*===========================================================================*/
        -:   51:
        -:   52:/*===========================================================================*/
        -:   53:/* Module local functions.                                                   */
        -:   54:/*===========================================================================*/
        -:   55:
        -:   56:/*===========================================================================*/
        -:   57:/* Module exported functions.                                                */
        -:   58:/*===========================================================================*/
        -:   59:
        -:   60:/**
        -:   61: * @brief   Scheduler initialization.
        -:   62: *
        -:   63: * @notapi
        -:   64: */
function _scheduler_init called 1 returned 100% blocks executed 100%
        1:   65:void _scheduler_init(void) {
        -:   66:
        1:   67:  queue_init(&ch.rlist.r_queue);
call    0 returned 100%
        1:   68:  ch.rlist.r_prio = NOPRIO;
        -:   69:#if CH_CFG_USE_REGISTRY == TRUE
        1:   70:  ch.rlist.r_newer = (thread_t *)&ch.rlist;
        1:   71:  ch.rlist.r_older = (thread_t *)&ch.rlist;
        -:   72:#endif
        1:   73:}
        -:   74:
        -:   75:#if (CH_CFG_OPTIMIZE_SPEED == FALSE) || defined(__DOXYGEN__)
        -:   76:/**
        -:   77: * @brief   Inserts a thread into a priority ordered queue.
        -:   78: * @note    The insertion is done by scanning the list from the highest
        -:   79: *          priority toward the lowest.
        -:   80: *
        -:   81: * @param[in] tp        the pointer to the thread to be inserted in the list
        -:   82: * @param[in] tqp       the pointer to the threads list header
        -:   83: *
        -:   84: * @notapi
        -:   85: */
        -:   86:void queue_prio_insert(thread_t *tp, threads_queue_t *tqp) {
        -:   87:
        -:   88:  thread_t *cp = (thread_t *)tqp;
        -:   89:  do {
        -:   90:    cp = cp->p_next;
        -:   91:  } while ((cp != (thread_t *)tqp) && (cp->p_prio >= tp->p_prio));
        -:   92:  tp->p_next = cp;
        -:   93:  tp->p_prev = cp->p_prev;
        -:   94:  tp->p_prev->p_next = tp;
        -:   95:  cp->p_prev = tp;
        -:   96:}
        -:   97:
        -:   98:/**
        -:   99: * @brief   Inserts a thread into a queue.
        -:  100: *
        -:  101: * @param[in] tp        the pointer to the thread to be inserted in the list
        -:  102: * @param[in] tqp       the pointer to the threads list header
        -:  103: *
        -:  104: * @notapi
        -:  105: */
        -:  106:void queue_insert(thread_t *tp, threads_queue_t *tqp) {
        -:  107:
        -:  108:  tp->p_next = (thread_t *)tqp;
        -:  109:  tp->p_prev = tqp->p_prev;
        -:  110:  tp->p_prev->p_next = tp;
        -:  111:  tqp->p_prev = tp;
        -:  112:}
        -:  113:
        -:  114:/**
        -:  115: * @brief   Removes the first-out thread from a queue and returns it.
        -:  116: * @note    If the queue is priority ordered then this function returns the
        -:  117: *          thread with the highest priority.
        -:  118: *
        -:  119: * @param[in] tqp       the pointer to the threads list header
        -:  120: * @return              The removed thread pointer.
        -:  121: *
        -:  122: * @notapi
        -:  123: */
        -:  124:thread_t *queue_fifo_remove(threads_queue_t *tqp) {
        -:  125:  thread_t *tp = tqp->p_next;
        -:  126:
        -:  127:  tqp->p_next = tp->p_next;
        -:  128:  tqp->p_next->p_prev = (thread_t *)tqp;
        -:  129:
        -:  130:  return tp;
        -:  131:}
        -:  132:
        -:  133:/**
        -:  134: * @brief   Removes the last-out thread from a queue and returns it.
        -:  135: * @note    If the queue is priority ordered then this function returns the
        -:  136: *          thread with the lowest priority.
        -:  137: *
        -:  138: * @param[in] tqp   the pointer to the threads list header
        -:  139: * @return          The removed thread pointer.
        -:  140: *
        -:  141: * @notapi
        -:  142: */
        -:  143:thread_t *queue_lifo_remove(threads_queue_t *tqp) {
        -:  144:  thread_t *tp = tqp->p_prev;
        -:  145:
        -:  146:  tqp->p_prev = tp->p_prev;
        -:  147:  tqp->p_prev->p_next = (thread_t *)tqp;
        -:  148:
        -:  149:  return tp;
        -:  150:}
        -:  151:
        -:  152:/**
        -:  153: * @brief   Removes a thread from a queue and returns it.
        -:  154: * @details The thread is removed from the queue regardless of its relative
        -:  155: *          position and regardless the used insertion method.
        -:  156: *
        -:  157: * @param[in] tp        the pointer to the thread to be removed from the queue
        -:  158: * @return              The removed thread pointer.
        -:  159: *
        -:  160: * @notapi
        -:  161: */
        -:  162:thread_t *queue_dequeue(thread_t *tp) {
        -:  163:
        -:  164:  tp->p_prev->p_next = tp->p_next;
        -:  165:  tp->p_next->p_prev = tp->p_prev;
        -:  166:
        -:  167:  return tp;
        -:  168:}
        -:  169:
        -:  170:/**
        -:  171: * @brief   Pushes a thread_t on top of a stack list.
        -:  172: *
        -:  173: * @param[in] tp    the pointer to the thread to be inserted in the list
        -:  174: * @param[in] tlp   the pointer to the threads list header
        -:  175: *
        -:  176: * @notapi
        -:  177: */
        -:  178:void list_insert(thread_t *tp, threads_list_t *tlp) {
        -:  179:
        -:  180:  tp->p_next = tlp->p_next;
        -:  181:  tlp->p_next = tp;
        -:  182:}
        -:  183:
        -:  184:/**
        -:  185: * @brief   Pops a thread from the top of a stack list and returns it.
        -:  186: * @pre     The list must be non-empty before calling this function.
        -:  187: *
        -:  188: * @param[in] tlp       the pointer to the threads list header
        -:  189: * @return              The removed thread pointer.
        -:  190: *
        -:  191: * @notapi
        -:  192: */
        -:  193:thread_t *list_remove(threads_list_t *tlp) {
        -:  194:
        -:  195:  thread_t *tp = tlp->p_next;
        -:  196:  tlp->p_next = tp->p_next;
        -:  197:
        -:  198:  return tp;
        -:  199:}
        -:  200:#endif /* CH_CFG_OPTIMIZE_SPEED */
        -:  201:
        -:  202:/**
        -:  203: * @brief   Inserts a thread in the Ready List.
        -:  204: * @details The thread is positioned behind all threads with higher or equal
        -:  205: *          priority.
        -:  206: * @pre     The thread must not be already inserted in any list through its
        -:  207: *          @p p_next and @p p_prev or list corruption would occur.
        -:  208: * @post    This function does not reschedule so a call to a rescheduling
        -:  209: *          function must be performed before unlocking the kernel. Note that
        -:  210: *          interrupt handlers always reschedule on exit so an explicit
        -:  211: *          reschedule must not be performed in ISRs.
        -:  212: *
        -:  213: * @param[in] tp        the thread to be made ready
        -:  214: * @return              The thread pointer.
        -:  215: *
        -:  216: * @iclass
        -:  217: */
function chSchReadyI called 29851513 returned 100% blocks executed 100%
 29851513:  218:thread_t *chSchReadyI(thread_t *tp) {
unconditional  0 taken 100%
        -:  219:  thread_t *cp;
        -:  220:
        -:  221:  chDbgCheckClassI();
        -:  222:  chDbgCheck(tp != NULL);
        -:  223:  chDbgAssert((tp->p_state != CH_STATE_READY) &&
        -:  224:              (tp->p_state != CH_STATE_FINAL),
        -:  225:              "invalid state");
        -:  226:
 29851513:  227:  tp->p_state = CH_STATE_READY;
 29851513:  228:  cp = (thread_t *)&ch.rlist.r_queue;
unconditional  0 taken 100%
        -:  229:  do {
 47365897:  230:    cp = cp->p_next;
 47365897:  231:  } while (cp->p_prio >= tp->p_prio);
branch  0 taken 37%
branch  1 taken 63% (fallthrough)
        -:  232:  /* Insertion on p_prev.*/
 29851513:  233:  tp->p_next = cp;
 29851513:  234:  tp->p_prev = cp->p_prev;
 29851513:  235:  tp->p_prev->p_next = tp;
 29851513:  236:  cp->p_prev = tp;
        -:  237:
 29851513:  238:  return tp;
unconditional  0 taken 100%
        -:  239:}
        -:  240:
        -:  241:/**
        -:  242: * @brief   Puts the current thread to sleep into the specified state.
        -:  243: * @details The thread goes into a sleeping state. The possible
        -:  244: *          @ref thread_states are defined into @p threads.h.
        -:  245: *
        -:  246: * @param[in] newstate  the new thread state
        -:  247: *
        -:  248: * @sclass
        -:  249: */
function chSchGoSleepS called 24013356 returned 86% blocks executed 100%
 24013356:  250:void chSchGoSleepS(tstate_t newstate) {
        -:  251:  thread_t *otp;
        -:  252:
        -:  253:  chDbgCheckClassS();
        -:  254:
 24013356:  255:  otp = currp;
 24013356:  256:  otp->p_state = newstate;
        -:  257:#if CH_CFG_TIME_QUANTUM > 0
        -:  258:  /* The thread is renouncing its remaining time slices so it will have a new
        -:  259:     time quantum when it will wakeup.*/
 24013356:  260:  otp->p_preempt = (tslices_t)CH_CFG_TIME_QUANTUM;
        -:  261:#endif
 24013356:  262:  setcurrp(queue_fifo_remove(&ch.rlist.r_queue));
call    0 returned 100%
        -:  263:#if defined(CH_CFG_IDLE_ENTER_HOOK)
 24013356:  264:  if (currp->p_prio == IDLEPRIO) {
unconditional  0 taken 100%
        -:  265:    CH_CFG_IDLE_ENTER_HOOK();
        -:  266:  }
        -:  267:#endif
 24013356:  268:  currp->p_state = CH_STATE_CURRENT;
 24013356:  269:  chSysSwitch(currp, otp);
call    0 returned 86%
 20756272:  270:}
        -:  271:
        -:  272:/*
        -:  273: * Timeout wakeup callback.
        -:  274: */
function wakeup called 61 returned 100% blocks executed 75%
       61:  275:static void wakeup(void *p) {
       61:  276:  thread_t *tp = (thread_t *)p;
        -:  277:
       61:  278:  chSysLockFromISR();
call    0 returned 100%
       61:  279:  switch (tp->p_state) {
branch  0 taken 0%
branch  1 taken 0%
branch  2 taken 13%
branch  3 taken 7%
branch  4 taken 80%
        -:  280:  case CH_STATE_READY:
        -:  281:    /* Handling the special case where the thread has been made ready by
        -:  282:       another thread with higher priority.*/
    #####:  283:    chSysUnlockFromISR();
call    0 never executed
       61:  284:    return;
unconditional  0 never executed
        -:  285:  case CH_STATE_SUSPENDED:
    #####:  286:    *tp->p_u.wttrp = NULL;
    #####:  287:    break;
unconditional  0 never executed
        -:  288:#if CH_CFG_USE_SEMAPHORES == TRUE
        -:  289:  case CH_STATE_WTSEM:
        8:  290:    chSemFastSignalI(tp->p_u.wtsemp);
call    0 returned 100%
unconditional  1 taken 100%
        -:  291:    /* Falls into, intentional. */
        -:  292:#endif
        -:  293:#if (CH_CFG_USE_CONDVARS == TRUE) && (CH_CFG_USE_CONDVARS_TIMEOUT == TRUE)
        -:  294:  case CH_STATE_WTCOND:
        -:  295:#endif
        -:  296:  case CH_STATE_QUEUED:
        -:  297:    /* States requiring dequeuing.*/
       12:  298:    (void) queue_dequeue(tp);
call    0 returned 100%
       12:  299:    break;
unconditional  0 taken 100%
        -:  300:  default:
        -:  301:    /* Any other state, nothing to do.*/
       49:  302:    break;
unconditional  0 taken 100%
        -:  303:  }
       61:  304:  tp->p_u.rdymsg = MSG_TIMEOUT;
       61:  305:  (void) chSchReadyI(tp);
call    0 returned 100%
       61:  306:  chSysUnlockFromISR();
call    0 returned 100%
unconditional  1 taken 100%
        -:  307:}
        -:  308:
        -:  309:/**
        -:  310: * @brief   Puts the current thread to sleep into the specified state with
        -:  311: *          timeout specification.
        -:  312: * @details The thread goes into a sleeping state, if it is not awakened
        -:  313: *          explicitly within the specified timeout then it is forcibly
        -:  314: *          awakened with a @p MSG_TIMEOUT low level message. The possible
        -:  315: *          @ref thread_states are defined into @p threads.h.
        -:  316: *
        -:  317: * @param[in] newstate  the new thread state
        -:  318: * @param[in] time      the number of ticks before the operation timeouts, the
        -:  319: *                      special values are handled as follow:
        -:  320: *                      - @a TIME_INFINITE the thread enters an infinite sleep
        -:  321: *                        state, this is equivalent to invoking
        -:  322: *                        @p chSchGoSleepS() but, of course, less efficient.
        -:  323: *                      - @a TIME_IMMEDIATE this value is not allowed.
        -:  324: *                      .
        -:  325: * @return              The wakeup message.
        -:  326: * @retval MSG_TIMEOUT  if a timeout occurs.
        -:  327: *
        -:  328: * @sclass
        -:  329: */
function chSchGoSleepTimeoutS called 63 returned 100% blocks executed 100%
       63:  330:msg_t chSchGoSleepTimeoutS(tstate_t newstate, systime_t time) {
        -:  331:
        -:  332:  chDbgCheckClassS();
        -:  333:
       63:  334:  if (TIME_INFINITE != time) {
branch  0 taken 98% (fallthrough)
branch  1 taken 2%
        -:  335:    virtual_timer_t vt;
        -:  336:
       62:  337:    chVTDoSetI(&vt, time, wakeup, currp);
call    0 returned 100%
       62:  338:    chSchGoSleepS(newstate);
call    0 returned 100%
       62:  339:    if (chVTIsArmedI(&vt)) {
call    0 returned 100%
branch  1 taken 2% (fallthrough)
branch  2 taken 98%
        1:  340:      chVTDoResetI(&vt);
call    0 returned 100%
unconditional  1 taken 100%
unconditional  2 taken 100%
        -:  341:    }
        -:  342:  }
        -:  343:  else {
        1:  344:    chSchGoSleepS(newstate);
call    0 returned 100%
unconditional  1 taken 100%
        -:  345:  }
        -:  346:
       63:  347:  return currp->p_u.rdymsg;
unconditional  0 taken 100%
        -:  348:}
        -:  349:
        -:  350:/**
        -:  351: * @brief   Wakes up a thread.
        -:  352: * @details The thread is inserted into the ready list or immediately made
        -:  353: *          running depending on its relative priority compared to the current
        -:  354: *          thread.
        -:  355: * @pre     The thread must not be already inserted in any list through its
        -:  356: *          @p p_next and @p p_prev or list corruption would occur.
        -:  357: * @note    It is equivalent to a @p chSchReadyI() followed by a
        -:  358: *          @p chSchRescheduleS() but much more efficient.
        -:  359: * @note    The function assumes that the current thread has the highest
        -:  360: *          priority.
        -:  361: *
        -:  362: * @param[in] ntp       the thread to be made ready
        -:  363: * @param[in] msg       the wakeup message
        -:  364: *
        -:  365: * @sclass
        -:  366: */
function chSchWakeupS called 13897702 returned 100% blocks executed 100%
 13897702:  367:void chSchWakeupS(thread_t *ntp, msg_t msg) {
        -:  368:
        -:  369:  chDbgCheckClassS();
        -:  370:
        -:  371:  /* Storing the message to be retrieved by the target thread when it will
        -:  372:     restart execution.*/
 13897702:  373:  ntp->p_u.rdymsg = msg;
        -:  374:
        -:  375:  /* If the waken thread has a not-greater priority than the current
        -:  376:     one then it is just inserted in the ready list else it made
        -:  377:     running immediately and the invoking thread goes in the ready
        -:  378:     list instead.*/
 13897702:  379:  if (ntp->p_prio <= currp->p_prio) {
branch  0 taken 35% (fallthrough)
branch  1 taken 65%
  4855804:  380:    (void) chSchReadyI(ntp);
call    0 returned 100%
unconditional  1 taken 100%
        -:  381:  }
        -:  382:  else {
  9041898:  383:    thread_t *otp = chSchReadyI(currp);
call    0 returned 100%
  9041898:  384:    setcurrp(ntp);
        -:  385:#if defined(CH_CFG_IDLE_LEAVE_HOOK)
  9041898:  386:    if (otp->p_prio == IDLEPRIO) {
unconditional  0 taken 100%
        -:  387:      CH_CFG_IDLE_LEAVE_HOOK();
        -:  388:    }
        -:  389:#endif
  9041898:  390:    ntp->p_state = CH_STATE_CURRENT;
  9041898:  391:    chSysSwitch(ntp, otp);
call    0 returned 100%
unconditional  1 taken 100%
        -:  392:  }
 13897702:  393:}
        -:  394:
        -:  395:/**
        -:  396: * @brief   Performs a reschedule if a higher priority thread is runnable.
        -:  397: * @details If a thread with a higher priority than the current thread is in
        -:  398: *          the ready list then make the higher priority thread running.
        -:  399: *
        -:  400: * @sclass
        -:  401: */
function chSchRescheduleS called 1051993 returned 100% blocks executed 100%
  1051993:  402:void chSchRescheduleS(void) {
        -:  403:
        -:  404:  chDbgCheckClassS();
        -:  405:
  1051993:  406:  if (chSchIsRescRequiredI()) {
call    0 returned 100%
branch  1 taken 99% (fallthrough)
branch  2 taken 1%
  1051969:  407:    chSchDoRescheduleAhead();
call    0 returned 100%
unconditional  1 taken 100%
        -:  408:  }
  1051993:  409:}
        -:  410:
        -:  411:/**
        -:  412: * @brief   Evaluates if preemption is required.
        -:  413: * @details The decision is taken by comparing the relative priorities and
        -:  414: *          depending on the state of the round robin timeout counter.
        -:  415: * @note    Not a user function, it is meant to be invoked by the scheduler
        -:  416: *          itself or from within the port layer.
        -:  417: *
        -:  418: * @retval true         if there is a thread that must go in running state
        -:  419: *                      immediately.
        -:  420: * @retval false        if preemption is not required.
        -:  421: *
        -:  422: * @special
        -:  423: */
function chSchIsPreemptionRequired called 15092 returned 100% blocks executed 100%
    15092:  424:bool chSchIsPreemptionRequired(void) {
    15092:  425:  tprio_t p1 = firstprio(&ch.rlist.r_queue);
    15092:  426:  tprio_t p2 = currp->p_prio;
        -:  427:
        -:  428:#if CH_CFG_TIME_QUANTUM > 0
        -:  429:  /* If the running thread has not reached its time quantum, reschedule only
        -:  430:     if the first thread on the ready queue has a higher priority.
        -:  431:     Otherwise, if the running thread has used up its time quantum, reschedule
        -:  432:     if the first thread on the ready queue has equal or higher priority.*/
    15092:  433:  return (currp->p_preempt > (tslices_t)0) ? (p1 > p2) : (p1 >= p2);
branch  0 taken 39% (fallthrough)
branch  1 taken 61%
unconditional  2 taken 100%
unconditional  3 taken 100%
unconditional  4 taken 100%
        -:  434:#else
        -:  435:  /* If the round robin preemption feature is not enabled then performs a
        -:  436:     simpler comparison.*/
        -:  437:  return p1 > p2;
        -:  438:#endif
        -:  439:}
        -:  440:
        -:  441:/**
        -:  442: * @brief   Switches to the first thread on the runnable queue.
        -:  443: * @details The current thread is positioned in the ready list behind all
        -:  444: *          threads having the same priority. The thread regains its time
        -:  445: *          quantum.
        -:  446: * @note    Not a user function, it is meant to be invoked by the scheduler
        -:  447: *          itself or from within the port layer.
        -:  448: *
        -:  449: * @special
        -:  450: */
function chSchDoRescheduleBehind called 5838147 returned 100% blocks executed 100%
  5838147:  451:void chSchDoRescheduleBehind(void) {
        -:  452:  thread_t *otp;
        -:  453:
  5838147:  454:  otp = currp;
        -:  455:  /* Picks the first thread from the ready queue and makes it current.*/
  5838147:  456:  setcurrp(queue_fifo_remove(&ch.rlist.r_queue));
call    0 returned 100%
        -:  457:#if defined(CH_CFG_IDLE_LEAVE_HOOK)
  5838147:  458:  if (otp->p_prio == IDLEPRIO) {
unconditional  0 taken 100%
        -:  459:    CH_CFG_IDLE_LEAVE_HOOK();
        -:  460:  }
        -:  461:#endif
  5838147:  462:  currp->p_state = CH_STATE_CURRENT;
        -:  463:#if CH_CFG_TIME_QUANTUM > 0
  5838147:  464:  otp->p_preempt = (tslices_t)CH_CFG_TIME_QUANTUM;
        -:  465:#endif
  5838147:  466:  (void) chSchReadyI(otp);
call    0 returned 100%
  5838147:  467:  chSysSwitch(currp, otp);
call    0 returned 100%
  5838147:  468:}
        -:  469:
        -:  470:/**
        -:  471: * @brief   Switches to the first thread on the runnable queue.
        -:  472: * @details The current thread is positioned in the ready list ahead of all
        -:  473: *          threads having the same priority.
        -:  474: * @note    Not a user function, it is meant to be invoked by the scheduler
        -:  475: *          itself or from within the port layer.
        -:  476: *
        -:  477: * @special
        -:  478: */
function chSchDoRescheduleAhead called 1051999 returned 99% blocks executed 100%
  1051999:  479:void chSchDoRescheduleAhead(void) {
        -:  480:  thread_t *otp, *cp;
        -:  481:
  1051999:  482:  otp = currp;
        -:  483:  /* Picks the first thread from the ready queue and makes it current.*/
  1051999:  484:  setcurrp(queue_fifo_remove(&ch.rlist.r_queue));
call    0 returned 100%
        -:  485:#if defined(CH_CFG_IDLE_LEAVE_HOOK)
  1051999:  486:  if (otp->p_prio == IDLEPRIO) {
unconditional  0 taken 100%
        -:  487:    CH_CFG_IDLE_LEAVE_HOOK();
        -:  488:  }
        -:  489:#endif
  1051999:  490:  currp->p_state = CH_STATE_CURRENT;
        -:  491:
  1051999:  492:  otp->p_state = CH_STATE_READY;
  1051999:  493:  cp = (thread_t *)&ch.rlist.r_queue;
unconditional  0 taken 100%
        -:  494:  do {
  5259839:  495:    cp = cp->p_next;
  5259839:  496:  } while (cp->p_prio > otp->p_prio);
branch  0 taken 80%
branch  1 taken 20% (fallthrough)
        -:  497:  /* Insertion on p_prev.*/
  1051999:  498:  otp->p_next = cp;
  1051999:  499:  otp->p_prev = cp->p_prev;
  1051999:  500:  otp->p_prev->p_next = otp;
  1051999:  501:  cp->p_prev = otp;
        -:  502:
  1051999:  503:  chSysSwitch(currp, otp);
call    0 returned 99%
  1051998:  504:}
        -:  505:
        -:  506:/**
        -:  507: * @brief   Switches to the first thread on the runnable queue.
        -:  508: * @details The current thread is positioned in the ready list behind or
        -:  509: *          ahead of all threads having the same priority depending on
        -:  510: *          if it used its whole time slice.
        -:  511: * @note    Not a user function, it is meant to be invoked by the scheduler
        -:  512: *          itself or from within the port layer.
        -:  513: *
        -:  514: * @special
        -:  515: */
function chSchDoReschedule called 61 returned 98% blocks executed 100%
       61:  516:void chSchDoReschedule(void) {
        -:  517:
        -:  518:#if CH_CFG_TIME_QUANTUM > 0
        -:  519:  /* If CH_CFG_TIME_QUANTUM is enabled then there are two different scenarios
        -:  520:     to handle on preemption: time quantum elapsed or not.*/
       61:  521:  if (currp->p_preempt == (tslices_t)0) {
branch  0 taken 51% (fallthrough)
branch  1 taken 49%
        -:  522:    /* The thread consumed its time quantum so it is enqueued behind threads
        -:  523:       with same priority level, however, it acquires a new time quantum.*/
       31:  524:    chSchDoRescheduleBehind();
call    0 returned 100%
unconditional  1 taken 100%
        -:  525:  }
        -:  526:  else {
        -:  527:    /* The thread didn't consume all its time quantum so it is put ahead of
        -:  528:       threads with equal priority and does not acquire a new time quantum.*/
       30:  529:    chSchDoRescheduleAhead();
call    0 returned 97%
unconditional  1 taken 97%
        -:  530:  }
        -:  531:#else /* !(CH_CFG_TIME_QUANTUM > 0) */
        -:  532:  /* If the round-robin mechanism is disabled then the thread goes always
        -:  533:     ahead of its peers.*/
        -:  534:  chSchDoRescheduleAhead();
        -:  535:#endif /* !(CH_CFG_TIME_QUANTUM > 0) */
       60:  536:}
        -:  537:
        -:  538:/** @} */
