Пример #1
0
/**
 * @brief   Unlocks the specified mutex.
 * @note    Mutexes must be unlocked in reverse lock order. Violating this
 *          rules will result in a panic if assertions are enabled.
 * @pre     The invoking thread <b>must</b> have at least one owned mutex.
 * @post    The mutex is unlocked and removed from the per-thread stack of
 *          owned mutexes.
 * @post    This function does not reschedule so a call to a rescheduling
 *          function must be performed before unlocking the kernel.
 *
 * @param[in] mp        pointer to the @p mutex_t structure
 *
 * @sclass
 */
void chMtxUnlockS(mutex_t *mp) {
    thread_t *ctp = currp;
    mutex_t *lmp;

    chDbgCheckClassS();
    chDbgCheck(mp != NULL);

    chDbgAssert(ctp->p_mtxlist != NULL, "owned mutexes list empty");
    chDbgAssert(ctp->p_mtxlist->m_owner == ctp, "ownership failure");
#if CH_CFG_USE_MUTEXES_RECURSIVE
    chDbgAssert(mp->m_cnt >= 1, "counter is not positive");

    if (--mp->m_cnt == 0) {
#endif

        chDbgAssert(ctp->p_mtxlist == mp, "not next in list");

        /* Removes the top mutex from the thread's owned mutexes list and marks
           it as not owned. Note, it is assumed to be the same mutex passed as
           parameter of this function.*/
        ctp->p_mtxlist = mp->m_next;

        /* If a thread is waiting on the mutex then the fun part begins.*/
        if (chMtxQueueNotEmptyS(mp)) {
            thread_t *tp;

            /* Recalculates the optimal thread priority by scanning the owned
               mutexes list.*/
            tprio_t newprio = ctp->p_realprio;
            lmp = ctp->p_mtxlist;
            while (lmp != NULL) {
                /* If the highest priority thread waiting in the mutexes list has a
                   greater priority than the current thread base priority then the
                   final priority will have at least that priority.*/
                if (chMtxQueueNotEmptyS(lmp) && (lmp->m_queue.p_next->p_prio > newprio))
                    newprio = lmp->m_queue.p_next->p_prio;
                lmp = lmp->m_next;
            }

            /* Assigns to the current thread the highest priority among all the
               waiting threads.*/
            ctp->p_prio = newprio;

            /* Awakens the highest priority thread waiting for the unlocked mutex and
               assigns the mutex to it.*/
#if CH_CFG_USE_MUTEXES_RECURSIVE
            mp->m_cnt = 1;
#endif
            tp = queue_fifo_remove(&mp->m_queue);
            mp->m_owner = tp;
            mp->m_next = tp->p_mtxlist;
            tp->p_mtxlist = mp;
            chSchReadyI(tp);
        }
        else
            mp->m_owner = NULL;
#if CH_CFG_USE_MUTEXES_RECURSIVE
    }
#endif
}
Пример #2
0
/**
 * @brief   Unlocks all mutexes owned by the invoking thread.
 * @post    The stack of owned mutexes is emptied and all the found
 *          mutexes are unlocked.
 * @note    This function is <b>MUCH MORE</b> efficient than releasing the
 *          mutexes one by one and not just because the call overhead,
 *          this function does not have any overhead related to the priority
 *          inheritance mechanism.
 *
 * @api
 */
void chMtxUnlockAll(void) {
  thread_t *ctp = currp;

  chSysLock();
  if (ctp->p_mtxlist != NULL) {
    do {
      mutex_t *mp = ctp->p_mtxlist;
      ctp->p_mtxlist = mp->m_next;
      if (chMtxQueueNotEmptyS(mp)) {
#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
        mp->m_cnt = (cnt_t)1;
#endif
        thread_t *tp = queue_fifo_remove(&mp->m_queue);
        mp->m_owner = tp;
        mp->m_next = tp->p_mtxlist;
        tp->p_mtxlist = mp;
        (void) chSchReadyI(tp);
      }
      else {
#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
        mp->m_cnt = (cnt_t)0;
#endif
        mp->m_owner = NULL;
      }
    } while (ctp->p_mtxlist != NULL);
    ctp->p_prio = ctp->p_realprio;
    chSchRescheduleS();
  }
  chSysUnlock();
}
Пример #3
0
/**
 * @brief   Performs atomic signal and wait operations on two semaphores.
 *
 * @param[in] sps       pointer to a @p semaphore_t structure to be signaled
 * @param[in] spw       pointer to a @p semaphore_t structure to wait on
 * @return              A message specifying how the invoking thread has been
 *                      released from the semaphore.
 * @retval MSG_OK       if the thread has not stopped on the semaphore or the
 *                      semaphore has been signaled.
 * @retval MSG_RESET    if the semaphore has been reset using @p chSemReset().
 *
 * @api
 */
msg_t chSemSignalWait(semaphore_t *sps, semaphore_t *spw) {
  msg_t msg;

  chDbgCheck((sps != NULL) && (spw != NULL));
  chDbgAssert(((sps->s_cnt >= (cnt_t)0) && queue_isempty(&sps->s_queue)) ||
              ((sps->s_cnt < (cnt_t)0) && queue_notempty(&sps->s_queue)),
              "inconsistent semaphore");
  chDbgAssert(((spw->s_cnt >= (cnt_t)0) && queue_isempty(&spw->s_queue)) ||
              ((spw->s_cnt < (cnt_t)0) && queue_notempty(&spw->s_queue)),
              "inconsistent semaphore");

  chSysLock();
  if (++sps->s_cnt <= (cnt_t)0) {
    chSchReadyI(queue_fifo_remove(&sps->s_queue))->p_u.rdymsg = MSG_OK;
  }
  if (--spw->s_cnt < (cnt_t)0) {
    thread_t *ctp = currp;
    sem_insert(ctp, &spw->s_queue);
    ctp->p_u.wtsemp = spw;
    chSchGoSleepS(CH_STATE_WTSEM);
    msg = ctp->p_u.rdymsg;
  }
  else {
    chSchRescheduleS();
    msg = MSG_OK;
  }
  chSysUnlock();

  return msg;
}
Пример #4
0
/**
 * @brief   Unlocks all mutexes owned by the invoking thread.
 * @post    The stack of owned mutexes is emptied and all the found
 *          mutexes are unlocked.
 * @post    This function does not reschedule so a call to a rescheduling
 *          function must be performed before unlocking the kernel.
 * @note    This function is <b>MUCH MORE</b> efficient than releasing the
 *          mutexes one by one and not just because the call overhead,
 *          this function does not have any overhead related to the priority
 *          inheritance mechanism.
 *
 * @sclass
 */
void chMtxUnlockAllS(void) {
  thread_t *ctp = currp;

  while (ctp->mtxlist != NULL) {
    mutex_t *mp = ctp->mtxlist;
    ctp->mtxlist = mp->next;
    if (chMtxQueueNotEmptyS(mp)) {
#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
      mp->cnt = (cnt_t)1;
#endif
      thread_t *tp = queue_fifo_remove(&mp->queue);
      mp->owner = tp;
      mp->next = tp->mtxlist;
      tp->mtxlist = mp;
      (void) chSchReadyI(tp);
    }
    else {
#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
      mp->cnt = (cnt_t)0;
#endif
      mp->owner = NULL;
    }
  }
  ctp->prio = ctp->realprio;
}
Пример #5
0
/**
 * @brief   Switches to the first thread on the runnable queue.
 * @details The current thread is positioned in the ready list ahead of all
 *          threads having the same priority.
 * @note    Not a user function, it is meant to be invoked by the scheduler
 *          itself or from within the port layer.
 *
 * @special
 */
void chSchDoRescheduleAhead(void) {
  thread_t *otp, *cp;

  otp = currp;
  /* Picks the first thread from the ready queue and makes it current.*/
  setcurrp(queue_fifo_remove(&ch.rlist.r_queue));
#if defined(CH_CFG_IDLE_LEAVE_HOOK)
  if (otp->p_prio == IDLEPRIO) {
    CH_CFG_IDLE_LEAVE_HOOK();
  }
#endif
  currp->p_state = CH_STATE_CURRENT;

  otp->p_state = CH_STATE_READY;
  cp = (thread_t *)&ch.rlist.r_queue;
  do {
    cp = cp->p_next;
  } while (cp->p_prio > otp->p_prio);
  /* Insertion on p_prev.*/
  otp->p_next = cp;
  otp->p_prev = cp->p_prev;
  otp->p_prev->p_next = cp->p_prev = otp;

  chSysSwitch(currp, otp);
}
Пример #6
0
/**
 * @brief   Signals one thread that is waiting on the condition variable.
 *
 * @param[in] cp        pointer to the @p condition_variable_t structure
 *
 * @api
 */
void chCondSignal(condition_variable_t *cp) {

  chDbgCheck(cp != NULL);

  chSysLock();
  if (queue_notempty(&cp->c_queue))
    chSchWakeupS(queue_fifo_remove(&cp->c_queue), MSG_OK);
  chSysUnlock();
}
Пример #7
0
/**
 * @brief   Suspends the thread and waits for an incoming message.
 * @post    After receiving a message the function @p chMsgGet() must be
 *          called in order to retrieve the message and then @p chMsgRelease()
 *          must be invoked in order to acknowledge the reception and send
 *          the answer.
 * @note    If the message is a pointer then you can assume that the data
 *          pointed by the message is stable until you invoke @p chMsgRelease()
 *          because the sending thread is suspended until then.
 *
 * @return              A reference to the thread carrying the message.
 *
 * @api
 */
thread_t *chMsgWait(void) {
  thread_t *tp;

  chSysLock();
  if (!chMsgIsPendingI(currp))
    chSchGoSleepS(CH_STATE_WTMSG);
  tp = queue_fifo_remove(&currp->p_msgqueue);
  tp->p_state = CH_STATE_SNDMSG;
  chSysUnlock();
  return tp;
}
Пример #8
0
/**
 * @brief   Signals one thread that is waiting on the condition variable.
 * @post    This function does not reschedule so a call to a rescheduling
 *          function must be performed before unlocking the kernel. Note that
 *          interrupt handlers always reschedule on exit so an explicit
 *          reschedule must not be performed in ISRs.
 *
 * @param[in] cp        pointer to the @p condition_variable_t structure
 *
 * @iclass
 */
void chCondSignalI(condition_variable_t *cp) {

  chDbgCheckClassI();
  chDbgCheck(cp != NULL);

  if (queue_notempty(&cp->c_queue)) {
    thread_t *tp = queue_fifo_remove(&cp->c_queue);
    tp->p_u.rdymsg = MSG_OK;
    chSchReadyI(tp);
  }
}
Пример #9
0
/**
 * @brief   Signals all threads that are waiting on the condition variable.
 * @post    This function does not reschedule so a call to a rescheduling
 *          function must be performed before unlocking the kernel. Note that
 *          interrupt handlers always reschedule on exit so an explicit
 *          reschedule must not be performed in ISRs.
 *
 * @param[in] cp        pointer to the @p condition_variable_t structure
 *
 * @iclass
 */
void chCondBroadcastI(condition_variable_t *cp) {

  chDbgCheckClassI();
  chDbgCheck(cp != NULL);

  /* Empties the condition variable queue and inserts all the threads into the
     ready list in FIFO order. The wakeup message is set to @p MSG_RESET in
     order to make a chCondBroadcast() detectable from a chCondSignal().*/
  while (cp->c_queue.p_next != (void *)&cp->c_queue)
    chSchReadyI(queue_fifo_remove(&cp->c_queue))->p_u.rdymsg = MSG_RESET;
}
Пример #10
0
/**
 * @brief   Performs a signal operation on a semaphore.
 *
 * @param[in] sp        pointer to a @p semaphore_t structure
 *
 * @api
 */
void chSemSignal(semaphore_t *sp) {

  chDbgCheck(sp != NULL);
  chDbgAssert(((sp->s_cnt >= 0) && queue_isempty(&sp->s_queue)) ||
              ((sp->s_cnt < 0) && queue_notempty(&sp->s_queue)),
              "inconsistent semaphore");

  chSysLock();
  if (++sp->s_cnt <= 0)
    chSchWakeupS(queue_fifo_remove(&sp->s_queue), MSG_OK);
  chSysUnlock();
}
Пример #11
0
/**
 * @brief   Adds the specified value to the semaphore counter.
 * @post    This function does not reschedule so a call to a rescheduling
 *          function must be performed before unlocking the kernel. Note that
 *          interrupt handlers always reschedule on exit so an explicit
 *          reschedule must not be performed in ISRs.
 *
 * @param[in] sp        pointer to a @p semaphore_t structure
 * @param[in] n         value to be added to the semaphore counter. The value
 *                      must be positive.
 *
 * @iclass
 */
void chSemAddCounterI(semaphore_t *sp, cnt_t n) {

  chDbgCheckClassI();
  chDbgCheck((sp != NULL) && (n > 0));
  chDbgAssert(((sp->s_cnt >= 0) && queue_isempty(&sp->s_queue)) ||
              ((sp->s_cnt < 0) && queue_notempty(&sp->s_queue)),
              "inconsistent semaphore");

  while (n > 0) {
    if (++sp->s_cnt <= 0)
      chSchReadyI(queue_fifo_remove(&sp->s_queue))->p_u.rdymsg = MSG_OK;
    n--;
  }
}
Пример #12
0
/**
 * @brief   Performs a signal operation on a semaphore.
 * @post    This function does not reschedule so a call to a rescheduling
 *          function must be performed before unlocking the kernel. Note that
 *          interrupt handlers always reschedule on exit so an explicit
 *          reschedule must not be performed in ISRs.
 *
 * @param[in] sp    pointer to a @p semaphore_t structure
 *
 * @iclass
 */
void chSemSignalI(semaphore_t *sp) {

  chDbgCheckClassI();
  chDbgCheck(sp != NULL);
  chDbgAssert(((sp->s_cnt >= (cnt_t)0) && queue_isempty(&sp->s_queue)) ||
              ((sp->s_cnt < (cnt_t)0) && queue_notempty(&sp->s_queue)),
              "inconsistent semaphore");

  if (++sp->s_cnt <= (cnt_t)0) {
    /* Note, it is done this way in order to allow a tail call on
             chSchReadyI().*/
    thread_t *tp = queue_fifo_remove(&sp->s_queue);
    tp->p_u.rdymsg = MSG_OK;
    (void) chSchReadyI(tp);
  }
}
Пример #13
0
/**
 * @brief   Switches to the first thread on the runnable queue.
 * @details The current thread is positioned in the ready list behind all
 *          threads having the same priority. The thread regains its time
 *          quantum.
 * @note    Not a user function, it is meant to be invoked by the scheduler
 *          itself or from within the port layer.
 *
 * @special
 */
void chSchDoRescheduleBehind(void) {
  thread_t *otp;

  otp = currp;
  /* Picks the first thread from the ready queue and makes it current.*/
  setcurrp(queue_fifo_remove(&ch.rlist.r_queue));
#if defined(CH_CFG_IDLE_LEAVE_HOOK)
  if (otp->p_prio == IDLEPRIO) {
    CH_CFG_IDLE_LEAVE_HOOK();
  }
#endif
  currp->p_state = CH_STATE_CURRENT;
#if CH_CFG_TIME_QUANTUM > 0
  otp->p_preempt = CH_CFG_TIME_QUANTUM;
#endif
  chSchReadyI(otp);
  chSysSwitch(currp, otp);
}
Пример #14
0
/**
 * @brief   Puts the current thread to sleep into the specified state.
 * @details The thread goes into a sleeping state. The possible
 *          @ref thread_states are defined into @p threads.h.
 *
 * @param[in] newstate  the new thread state
 *
 * @sclass
 */
void chSchGoSleepS(tstate_t newstate) {
  thread_t *otp;

  chDbgCheckClassS();

  (otp = currp)->p_state = newstate;
#if CH_CFG_TIME_QUANTUM > 0
  /* The thread is renouncing its remaining time slices so it will have a new
     time quantum when it will wakeup.*/
  otp->p_preempt = CH_CFG_TIME_QUANTUM;
#endif
  setcurrp(queue_fifo_remove(&ch.rlist.r_queue));
#if defined(CH_CFG_IDLE_ENTER_HOOK)
  if (currp->p_prio == IDLEPRIO) {
    CH_CFG_IDLE_ENTER_HOOK();
  }
#endif
  currp->p_state = CH_STATE_CURRENT;
  chSysSwitch(currp, otp);
}
Пример #15
0
/**
 * @brief   Unlocks the specified mutex.
 * @note    Mutexes must be unlocked in reverse lock order. Violating this
 *          rules will result in a panic if assertions are enabled.
 * @pre     The invoking thread <b>must</b> have at least one owned mutex.
 * @post    The mutex is unlocked and removed from the per-thread stack of
 *          owned mutexes.
 *
 * @param[in] mp        pointer to the @p mutex_t structure
 *
 * @api
 */
void chMtxUnlock(mutex_t *mp) {
  thread_t *ctp = currp;
  mutex_t *lmp;

  chDbgCheck(mp != NULL);

  chSysLock();

  chDbgAssert(ctp->mtxlist != NULL, "owned mutexes list empty");
  chDbgAssert(ctp->mtxlist->owner == ctp, "ownership failure");
#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
  chDbgAssert(mp->cnt >= (cnt_t)1, "counter is not positive");

  if (--mp->cnt == (cnt_t)0) {
#endif

    chDbgAssert(ctp->mtxlist == mp, "not next in list");

    /* Removes the top mutex from the thread's owned mutexes list and marks
       it as not owned. Note, it is assumed to be the same mutex passed as
       parameter of this function.*/
    ctp->mtxlist = mp->next;

    /* If a thread is waiting on the mutex then the fun part begins.*/
    if (chMtxQueueNotEmptyS(mp)) {
      thread_t *tp;

      /* Recalculates the optimal thread priority by scanning the owned
         mutexes list.*/
      tprio_t newprio = ctp->realprio;
      lmp = ctp->mtxlist;
      while (lmp != NULL) {
        /* If the highest priority thread waiting in the mutexes list has a
           greater priority than the current thread base priority then the
           final priority will have at least that priority.*/
        if (chMtxQueueNotEmptyS(lmp) &&
            (lmp->queue.next->prio > newprio)) {
          newprio = lmp->queue.next->prio;
        }
        lmp = lmp->next;
      }

      /* Assigns to the current thread the highest priority among all the
         waiting threads.*/
      ctp->prio = newprio;

      /* Awakens the highest priority thread waiting for the unlocked mutex and
         assigns the mutex to it.*/
#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
      mp->cnt = (cnt_t)1;
#endif
      tp = queue_fifo_remove(&mp->queue);
      mp->owner = tp;
      mp->next = tp->mtxlist;
      tp->mtxlist = mp;

      /* Note, not using chSchWakeupS() becuase that function expects the
         current thread to have the higher or equal priority than the ones
         in the ready list. This is not necessarily true here because we
         just changed priority.*/
      (void) chSchReadyI(tp);
      chSchRescheduleS();
    }
    else {
      mp->owner = NULL;
    }
#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
  }
#endif

  chSysUnlock();
}