/** * @brief Retrieves a message from a mailbox. * @details The invoking thread waits until a message is posted in the mailbox * or the specified time runs out. * * @param[in] mbp the pointer to an initialized @p mailbox_t object * @param[out] msgp pointer to a message variable for the received message * @param[in] timeout the number of ticks before the operation timeouts, * the following special values are allowed: * - @a TIME_IMMEDIATE immediate timeout. * - @a TIME_INFINITE no timeout. * . * @return The operation status. * @retval MSG_OK if a message has been correctly fetched. * @retval MSG_RESET if the mailbox has been reset. * @retval MSG_TIMEOUT if the operation has timed out. * * @sclass */ msg_t chMBFetchTimeoutS(mailbox_t *mbp, msg_t *msgp, sysinterval_t timeout) { msg_t rdymsg; chDbgCheckClassS(); chDbgCheck((mbp != NULL) && (msgp != NULL)); do { /* If the mailbox is in reset state then returns immediately.*/ if (mbp->reset) { return MSG_RESET; } /* Is there a message in queue? if so then fetch.*/ if (chMBGetUsedCountI(mbp) > (size_t)0) { *msgp = *mbp->rdptr++; if (mbp->rdptr >= mbp->top) { mbp->rdptr = mbp->buffer; } mbp->cnt--; /* If there is a writer waiting then makes it ready.*/ chThdDequeueNextI(&mbp->qw, MSG_OK); chSchRescheduleS(); return MSG_OK; } /* No message in the queue, waiting for a message to become available.*/ rdymsg = chThdEnqueueTimeoutS(&mbp->qr, timeout); } while (rdymsg == MSG_OK); return rdymsg; }
/** * @brief Tries to lock a mutex. * @details This function attempts to lock a mutex, if the mutex is already * taken by another thread then the function exits without waiting. * @post The mutex is locked and inserted in the per-thread stack of owned * mutexes. * @note This function does not have any overhead related to the * priority inheritance mechanism because it does not try to * enter a sleep state. * * @param[in] mp pointer to the @p mutex_t structure * @return The operation status. * @retval true if the mutex has been successfully acquired * @retval false if the lock attempt failed. * * @sclass */ bool chMtxTryLockS(mutex_t *mp) { chDbgCheckClassS(); chDbgCheck(mp != NULL); if (mp->m_owner != NULL) { #if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE chDbgAssert(mp->m_cnt >= (cnt_t)1, "counter is not positive"); if (mp->m_owner == currp) { mp->m_cnt++; return true; } #endif return false; } #if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE chDbgAssert(mp->m_cnt == (cnt_t)0, "counter is not zero"); mp->m_cnt++; #endif mp->m_owner = currp; mp->m_next = currp->p_mtxlist; currp->p_mtxlist = mp; return true; }
/** * @brief Wakes up a thread. * @details The thread is inserted into the ready list or immediately made * running depending on its relative priority compared to the current * thread. * @pre The thread must not be already inserted in any list through its * @p p_next and @p p_prev or list corruption would occur. * @note It is equivalent to a @p chSchReadyI() followed by a * @p chSchRescheduleS() but much more efficient. * @note The function assumes that the current thread has the highest * priority. * * @param[in] ntp the thread to be made ready * @param[in] msg the wakeup message * * @sclass */ void chSchWakeupS(thread_t *ntp, msg_t msg) { chDbgCheckClassS(); /* Storing the message to be retrieved by the target thread when it will restart execution.*/ ntp->p_u.rdymsg = msg; /* If the waken thread has a not-greater priority than the current one then it is just inserted in the ready list else it made running immediately and the invoking thread goes in the ready list instead.*/ if (ntp->p_prio <= currp->p_prio) { chSchReadyI(ntp); } else { thread_t *otp = chSchReadyI(currp); setcurrp(ntp); #if defined(CH_CFG_IDLE_LEAVE_HOOK) if (otp->p_prio == IDLEPRIO) { CH_CFG_IDLE_LEAVE_HOOK(); } #endif ntp->p_state = CH_STATE_CURRENT; chSysSwitch(ntp, otp); } }
/** * @brief Posts an high priority message into a mailbox. * @details The invoking thread waits until a empty slot in the mailbox becomes * available or the specified time runs out. * * @param[in] mbp the pointer to an initialized @p mailbox_t object * @param[in] msg the message to be posted on the mailbox * @param[in] timeout the number of ticks before the operation timeouts, * the following special values are allowed: * - @a TIME_IMMEDIATE immediate timeout. * - @a TIME_INFINITE no timeout. * . * @return The operation status. * @retval MSG_OK if a message has been correctly posted. * @retval MSG_RESET if the mailbox has been reset. * @retval MSG_TIMEOUT if the operation has timed out. * * @sclass */ msg_t chMBPostAheadTimeoutS(mailbox_t *mbp, msg_t msg, sysinterval_t timeout) { msg_t rdymsg; chDbgCheckClassS(); chDbgCheck(mbp != NULL); do { /* If the mailbox is in reset state then returns immediately.*/ if (mbp->reset) { return MSG_RESET; } /* Is there a free message slot in queue? if so then post.*/ if (chMBGetFreeCountI(mbp) > (size_t)0) { if (--mbp->rdptr < mbp->buffer) { mbp->rdptr = mbp->top - 1; } *mbp->rdptr = msg; mbp->cnt++; /* If there is a reader waiting then makes it ready.*/ chThdDequeueNextI(&mbp->qr, MSG_OK); chSchRescheduleS(); return MSG_OK; } /* No space in the queue, waiting for a slot to become available.*/ rdymsg = chThdEnqueueTimeoutS(&mbp->qw, timeout); } while (rdymsg == MSG_OK); return rdymsg; }
void chSchRescheduleS(void) { chDbgCheckClassS(); if (chSchIsRescRequiredI()) chSchDoRescheduleAhead(); }
/** * @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 }
/** * @brief Tries to lock a mutex. * @details This function attempts to lock a mutex, if the mutex is already * taken by another thread then the function exits without waiting. * @post The mutex is locked and inserted in the per-thread stack of owned * mutexes. * @note This function does not have any overhead related to the * priority inheritance mechanism because it does not try to * enter a sleep state. * * @param[in] mp pointer to the @p Mutex structure * @return The operation status. * @retval TRUE if the mutex has been successfully acquired * @retval FALSE if the lock attempt failed. * * @sclass */ bool_t chMtxTryLockS(Mutex *mp) { chDbgCheckClassS(); chDbgCheck(mp != NULL, "chMtxTryLockS"); if (mp->m_owner != NULL) return FALSE; mp->m_owner = currp; mp->m_next = currp->p_mtxlist; currp->p_mtxlist = mp; return TRUE; }
void chSchGoSleepS(tstate_t newstate) { Thread *otp; chDbgCheckClassS(); (otp = currp)->p_state = newstate; #if CH_TIME_QUANTUM > 0 rlist.r_preempt = CH_TIME_QUANTUM; #endif setcurrp(fifo_remove(&rlist.r_queue)); currp->p_state = THD_STATE_CURRENT; chSysSwitch(currp, otp); }
void chSchGoSleepS(tstate_t newstate) { Thread *otp; chDbgCheckClassS(); (otp = currp)->p_state = newstate; #if CH_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_TIME_QUANTUM; #endif setcurrp(fifo_remove(&rlist.r_queue)); currp->p_state = THD_STATE_CURRENT; chSysSwitch(currp, otp); }
/** * @brief Puts the current thread to sleep into the specified state with * timeout specification. * @details The thread goes into a sleeping state, if it is not awakened * explicitly within the specified timeout then it is forcibly * awakened with a @p RDY_TIMEOUT low level message. The possible * @ref thread_states are defined into @p threads.h. * * @param[in] newstate the new thread state * @param[in] time the number of ticks before the operation timeouts, the * special values are handled as follow: * - @a TIME_INFINITE the thread enters an infinite sleep * state, this is equivalent to invoking * @p chSchGoSleepS() but, of course, less efficient. * - @a TIME_IMMEDIATE this value is not allowed. * . * @return The wakeup message. * @retval RDY_TIMEOUT if a timeout occurs. * * @sclass */ msg_t chSchGoSleepTimeoutS(tstate_t newstate, systime_t time) { chDbgCheckClassS(); if (TIME_INFINITE != time) { VirtualTimer vt; chVTSetI(&vt, time, wakeup, currp); chSchGoSleepS(newstate); if (chVTIsArmedI(&vt)) chVTResetI(&vt); } else chSchGoSleepS(newstate); return currp->p_u.rdymsg; }
/** * @brief Performs a wait operation on a semaphore. * * @param[in] sp pointer to a @p semaphore_t structure * @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(). * * @sclass */ msg_t chSemWaitS(semaphore_t *sp) { chDbgCheckClassS(); chDbgCheck(sp != NULL); chDbgAssert(((sp->s_cnt >= 0) && queue_isempty(&sp->s_queue)) || ((sp->s_cnt < 0) && queue_notempty(&sp->s_queue)), "inconsistent semaphore"); if (--sp->s_cnt < 0) { currp->p_u.wtobjp = sp; sem_insert(currp, &sp->s_queue); chSchGoSleepS(CH_STATE_WTSEM); return currp->p_u.rdymsg; } return MSG_OK; }
/** * @brief Posts an high priority message into a mailbox. * @details The invoking thread waits until a empty slot in the mailbox becomes * available or the specified time runs out. * * @param[in] mbp the pointer to an initialized @p mailbox_t object * @param[in] msg the message to be posted on the mailbox * @param[in] time the number of ticks before the operation timeouts, * the following special values are allowed: * - @a TIME_IMMEDIATE immediate timeout. * - @a TIME_INFINITE no timeout. * . * @return The operation status. * @retval MSG_OK if a message has been correctly posted. * @retval MSG_RESET if the mailbox has been reset while waiting. * @retval MSG_TIMEOUT if the operation has timed out. * * @sclass */ msg_t chMBPostAheadS(mailbox_t *mbp, msg_t msg, systime_t time) { msg_t rdymsg; chDbgCheckClassS(); chDbgCheck(mbp != NULL); rdymsg = chSemWaitTimeoutS(&mbp->mb_emptysem, time); if (rdymsg == MSG_OK) { if (--mbp->mb_rdptr < mbp->mb_buffer) mbp->mb_rdptr = mbp->mb_top - 1; *mbp->mb_rdptr = msg; chSemSignalI(&mbp->mb_fullsem); chSchRescheduleS(); } return rdymsg; }
/** * @brief Retrieves a message from a mailbox. * @details The invoking thread waits until a message is posted in the mailbox * or the specified time runs out. * * @param[in] mbp the pointer to an initialized @p mailbox_t object * @param[out] msgp pointer to a message variable for the received message * @param[in] time the number of ticks before the operation timeouts, * the following special values are allowed: * - @a TIME_IMMEDIATE immediate timeout. * - @a TIME_INFINITE no timeout. * . * @return The operation status. * @retval MSG_OK if a message has been correctly fetched. * @retval MSG_RESET if the mailbox has been reset while waiting. * @retval MSG_TIMEOUT if the operation has timed out. * * @sclass */ msg_t chMBFetchS(mailbox_t *mbp, msg_t *msgp, systime_t time) { msg_t rdymsg; chDbgCheckClassS(); chDbgCheck((mbp != NULL) && (msgp != NULL)); rdymsg = chSemWaitTimeoutS(&mbp->mb_fullsem, time); if (rdymsg == MSG_OK) { *msgp = *mbp->mb_rdptr++; if (mbp->mb_rdptr >= mbp->mb_top) mbp->mb_rdptr = mbp->mb_buffer; chSemSignalI(&mbp->mb_emptysem); chSchRescheduleS(); } return rdymsg; }
/** * @brief Posts a message into a mailbox. * @details The invoking thread waits until a empty slot in the mailbox becomes * available or the specified time runs out. * * @param[in] mbp the pointer to an initialized Mailbox object * @param[in] msg the message to be posted on the mailbox * @param[in] time the number of ticks before the operation timeouts, * the following special values are allowed: * - @a TIME_IMMEDIATE immediate timeout. * - @a TIME_INFINITE no timeout. * . * @return The operation status. * @retval RDY_OK if a message has been correctly posted. * @retval RDY_RESET if the mailbox has been reset while waiting. * @retval RDY_TIMEOUT if the operation has timed out. * * @sclass */ msg_t chMBPostS(Mailbox *mbp, msg_t msg, systime_t time) { msg_t rdymsg; chDbgCheckClassS(); chDbgCheck(mbp != NULL, "chMBPostS"); rdymsg = chSemWaitTimeoutS(&mbp->mb_emptysem, time); if (rdymsg == RDY_OK) { *mbp->mb_wrptr++ = msg; if (mbp->mb_wrptr >= mbp->mb_top) mbp->mb_wrptr = mbp->mb_buffer; chSemSignalI(&mbp->mb_fullsem); chSchRescheduleS(); } return rdymsg; }
/** * @brief Performs a wait operation on a semaphore. * * @param[in] sp pointer to a @p Semaphore structure * @return A message specifying how the invoking thread has been * released from the semaphore. * @retval RDY_OK if the thread has not stopped on the semaphore or the * semaphore has been signaled. * @retval RDY_RESET if the semaphore has been reset using @p chSemReset(). * * @sclass */ msg_t chSemWaitS(Semaphore *sp) { chDbgCheckClassS(); chDbgCheck(sp != NULL, "chSemWaitS"); chDbgAssert(((sp->s_cnt >= 0) && isempty(&sp->s_queue)) || ((sp->s_cnt < 0) && notempty(&sp->s_queue)), "chSemWaitS(), #1", "inconsistent semaphore"); if (--sp->s_cnt < 0) { currp->p_u.wtobjp = sp; sem_insert(currp, &sp->s_queue); chSchGoSleepS(THD_STATE_WTSEM); return currp->p_u.rdymsg; } return RDY_OK; }
/** * @brief Waits on the condition variable releasing the mutex lock. * @details Releases the currently owned mutex, waits on the condition * variable, and finally acquires the mutex again. All the sequence * is performed atomically. * @pre The invoking thread <b>must</b> have at least one owned mutex. * @pre The configuration option @p CH_CFG_USE_CONDVARS_TIMEOUT must be enabled * in order to use this function. * @post Exiting the function because a timeout does not re-acquire the * mutex, the mutex ownership is lost. * * @param[in] cp pointer to the @p condition_variable_t structure * @param[in] time the number of ticks before the operation timeouts, the * special values are handled as follow: * - @a TIME_INFINITE no timeout. * - @a TIME_IMMEDIATE this value is not allowed. * . * @return A message specifying how the invoking thread has been * released from the condition variable. * @retval MSG_OK if the condition variable has been signaled using * @p chCondSignal(). * @retval MSG_RESET if the condition variable has been signaled using * @p chCondBroadcast(). * @retval MSG_TIMEOUT if the condition variable has not been signaled within * the specified timeout. * * @sclass */ msg_t chCondWaitTimeoutS(condition_variable_t *cp, systime_t time) { mutex_t *mp; msg_t msg; chDbgCheckClassS(); chDbgCheck((cp != NULL) && (time != TIME_IMMEDIATE)); chDbgAssert(currp->p_mtxlist != NULL, "not owning a mutex"); mp = chMtxGetNextMutexS(); chMtxUnlockS(mp); currp->p_u.wtobjp = cp; queue_prio_insert(currp, &cp->c_queue); msg = chSchGoSleepTimeoutS(CH_STATE_WTCOND, time); if (msg != MSG_TIMEOUT) chMtxLockS(mp); return msg; }
/** * @brief Unlocks the next owned mutex in reverse lock order. * @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. * * @return A pointer to the unlocked mutex. * * @sclass */ Mutex *chMtxUnlockS(void) { Thread *ctp = currp; Mutex *ump, *mp; chDbgCheckClassS(); chDbgAssert(ctp->p_mtxlist != NULL, "chMtxUnlockS(), #1", "owned mutexes list empty"); chDbgAssert(ctp->p_mtxlist->m_owner == ctp, "chMtxUnlockS(), #2", "ownership failure"); /* Removes the top Mutex from the owned mutexes list and marks it as not owned.*/ ump = ctp->p_mtxlist; ctp->p_mtxlist = ump->m_next; /* If a thread is waiting on the mutex then the fun part begins.*/ if (chMtxQueueNotEmptyS(ump)) { Thread *tp; /* Recalculates the optimal thread priority by scanning the owned mutexes list.*/ tprio_t newprio = ctp->p_realprio; mp = ctp->p_mtxlist; while (mp != 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(mp) && (mp->m_queue.p_next->p_prio > newprio)) newprio = mp->m_queue.p_next->p_prio; mp = mp->m_next; } ctp->p_prio = newprio; /* Awakens the highest priority thread waiting for the unlocked mutex and assigns the mutex to it.*/ tp = fifo_remove(&ump->m_queue); ump->m_owner = tp; ump->m_next = tp->p_mtxlist; tp->p_mtxlist = ump; chSchReadyI(tp); } else ump->m_owner = NULL; return ump; }
void chSchWakeupS(Thread *ntp, msg_t msg) { chDbgCheckClassS(); ntp->p_u.rdymsg = msg; /* If the waken thread has a not-greater priority than the current one then it is just inserted in the ready list else it made running immediately and the invoking thread goes in the ready list instead.*/ if (ntp->p_prio <= currp->p_prio) chSchReadyI(ntp); else { Thread *otp = chSchReadyI(currp); setcurrp(ntp); ntp->p_state = THD_STATE_CURRENT; chSysSwitch(ntp, otp); } }
/** * @brief Waits on the condition variable releasing the mutex lock. * @details Releases the currently owned mutex, waits on the condition * variable, and finally acquires the mutex again. All the sequence * is performed atomically. * @pre The invoking thread <b>must</b> have at least one owned mutex. * * @param[in] cp pointer to the @p condition_variable_t structure * @return A message specifying how the invoking thread has been * released from the condition variable. * @retval MSG_OK if the condition variable has been signaled using * @p chCondSignal(). * @retval MSG_RESET if the condition variable has been signaled using * @p chCondBroadcast(). * * @sclass */ msg_t chCondWaitS(condition_variable_t *cp) { thread_t *ctp = currp; mutex_t *mp; msg_t msg; chDbgCheckClassS(); chDbgCheck(cp != NULL); chDbgAssert(ctp->p_mtxlist != NULL, "not owning a mutex"); mp = chMtxGetNextMutexS(); chMtxUnlockS(mp); ctp->p_u.wtobjp = cp; queue_prio_insert(ctp, &cp->c_queue); chSchGoSleepS(CH_STATE_WTCOND); msg = ctp->p_u.rdymsg; chMtxLockS(mp); return msg; }
/** * @brief Performs a wait operation on a semaphore with timeout specification. * * @param[in] sp pointer to a @p semaphore_t structure * @param[in] time the number of ticks before the operation timeouts, * the following special values are allowed: * - @a TIME_IMMEDIATE immediate timeout. * - @a TIME_INFINITE no timeout. * . * @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(). * @retval MSG_TIMEOUT if the semaphore has not been signaled or reset within * the specified timeout. * * @sclass */ msg_t chSemWaitTimeoutS(semaphore_t *sp, systime_t time) { chDbgCheckClassS(); chDbgCheck(sp != NULL); chDbgAssert(((sp->s_cnt >= 0) && queue_isempty(&sp->s_queue)) || ((sp->s_cnt < 0) && queue_notempty(&sp->s_queue)), "inconsistent semaphore"); if (--sp->s_cnt < 0) { if (TIME_IMMEDIATE == time) { sp->s_cnt++; return MSG_TIMEOUT; } currp->p_u.wtobjp = sp; sem_insert(currp, &sp->s_queue); return chSchGoSleepTimeoutS(CH_STATE_WTSEM, time); } return MSG_OK; }
/** * @brief Performs a wait operation on a semaphore with timeout specification. * * @param[in] sp pointer to a @p semaphore_t structure * @param[in] timeout the number of ticks before the operation timeouts, * the following special values are allowed: * - @a TIME_IMMEDIATE immediate timeout. * - @a TIME_INFINITE no timeout. * . * @return A message specifying how the invoking thread has been * released from the semaphore. * @retval NIL_MSG_OK if the thread has not stopped on the semaphore or the * semaphore has been signaled. * @retval NIL_MSG_RST if the semaphore has been reset using @p chSemReset(). * @retval NIL_MSG_TMO if the semaphore has not been signaled or reset within * the specified timeout. * * @sclass */ msg_t chSemWaitTimeoutS(semaphore_t *sp, systime_t timeout) { chDbgCheckClassS(); chDbgCheck(sp != NULL); /* Note, the semaphore counter is a volatile variable so accesses are manually optimized.*/ cnt_t cnt = sp->cnt; if (cnt <= (cnt_t)0) { if (TIME_IMMEDIATE == timeout) { return MSG_TIMEOUT; } sp->cnt = cnt - (cnt_t)1; nil.current->u1.semp = sp; return chSchGoSleepTimeoutS(NIL_STATE_WTSEM, timeout); } sp->cnt = cnt - (cnt_t)1; return MSG_OK; }
/** * @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); }
/** * @brief Waits on the condition variable releasing the mutex lock. * @details Releases the currently owned mutex, waits on the condition * variable, and finally acquires the mutex again. All the sequence * is performed atomically. * @pre The invoking thread <b>must</b> have at least one owned mutex. * * @param[in] cp pointer to the @p condition_variable_t structure * @return A message specifying how the invoking thread has been * released from the condition variable. * @retval MSG_OK if the condition variable has been signaled using * @p chCondSignal(). * @retval MSG_RESET if the condition variable has been signaled using * @p chCondBroadcast(). * * @sclass */ msg_t chCondWaitS(condition_variable_t *cp) { thread_t *ctp = currp; mutex_t *mp; msg_t msg; chDbgCheckClassS(); chDbgCheck(cp != NULL); chDbgAssert(ctp->p_mtxlist != NULL, "not owning a mutex"); /* Getting "current" mutex and releasing it.*/ mp = chMtxGetNextMutexS(); chMtxUnlockS(mp); /* Start waiting on the condition variable, on exit the mutex is taken again.*/ ctp->p_u.wtobjp = cp; queue_prio_insert(ctp, &cp->c_queue); chSchGoSleepS(CH_STATE_WTCOND); msg = ctp->p_u.rdymsg; chMtxLockS(mp); return msg; }
/** * @brief Waits on the condition variable releasing the mutex lock. * @details Releases the currently owned mutex, waits on the condition * variable, and finally acquires the mutex again. All the sequence * is performed atomically. * @pre The invoking thread <b>must</b> have at least one owned mutex. * @pre The configuration option @p CH_CFG_USE_CONDVARS_TIMEOUT must be enabled * in order to use this function. * @post Exiting the function because a timeout does not re-acquire the * mutex, the mutex ownership is lost. * * @param[in] cp pointer to the @p condition_variable_t structure * @param[in] time the number of ticks before the operation timeouts, the * special values are handled as follow: * - @a TIME_INFINITE no timeout. * - @a TIME_IMMEDIATE this value is not allowed. * . * @return A message specifying how the invoking thread has been * released from the condition variable. * @retval MSG_OK if the condition variable has been signaled using * @p chCondSignal(). * @retval MSG_RESET if the condition variable has been signaled using * @p chCondBroadcast(). * @retval MSG_TIMEOUT if the condition variable has not been signaled within * the specified timeout. * * @sclass */ msg_t chCondWaitTimeoutS(condition_variable_t *cp, systime_t time) { mutex_t *mp; msg_t msg; chDbgCheckClassS(); chDbgCheck((cp != NULL) && (time != TIME_IMMEDIATE)); chDbgAssert(currp->p_mtxlist != NULL, "not owning a mutex"); /* Getting "current" mutex and releasing it.*/ mp = chMtxGetNextMutexS(); chMtxUnlockS(mp); /* Start waiting on the condition variable, on exit the mutex is taken again.*/ currp->p_u.wtobjp = cp; queue_prio_insert(currp, &cp->c_queue); msg = chSchGoSleepTimeoutS(CH_STATE_WTCOND, time); if (msg != MSG_TIMEOUT) { chMtxLockS(mp); } return msg; }
/** * @brief Locks the specified mutex. * @post The mutex is locked and inserted in the per-thread stack of owned * mutexes. * * @param[in] mp pointer to the @p mutex_t structure * * @sclass */ void chMtxLockS(mutex_t *mp) { thread_t *ctp = currp; chDbgCheckClassS(); chDbgCheck(mp != NULL); /* Is the mutex already locked? */ if (mp->m_owner != NULL) { #if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE chDbgAssert(mp->m_cnt >= (cnt_t)1, "counter is not positive"); /* If the mutex is already owned by this thread, the counter is increased and there is no need of more actions.*/ if (mp->m_owner == ctp) { mp->m_cnt++; } else { #endif /* Priority inheritance protocol; explores the thread-mutex dependencies boosting the priority of all the affected threads to equal the priority of the running thread requesting the mutex.*/ thread_t *tp = mp->m_owner; /* Does the running thread have higher priority than the mutex owning thread? */ while (tp->p_prio < ctp->p_prio) { /* Make priority of thread tp match the running thread's priority.*/ tp->p_prio = ctp->p_prio; /* The following states need priority queues reordering.*/ switch (tp->p_state) { case CH_STATE_WTMTX: /* Re-enqueues the mutex owner with its new priority.*/ queue_prio_insert(queue_dequeue(tp), &tp->p_u.wtmtxp->m_queue); tp = tp->p_u.wtmtxp->m_owner; /*lint -e{9042} [16.1] Continues the while.*/ continue; #if (CH_CFG_USE_CONDVARS == TRUE) || \ ((CH_CFG_USE_SEMAPHORES == TRUE) && \ (CH_CFG_USE_SEMAPHORES_PRIORITY == TRUE)) || \ ((CH_CFG_USE_MESSAGES == TRUE) && \ (CH_CFG_USE_MESSAGES_PRIORITY == TRUE)) #if CH_CFG_USE_CONDVARS == TRUE case CH_STATE_WTCOND: #endif #if (CH_CFG_USE_SEMAPHORES == TRUE) && \ (CH_CFG_USE_SEMAPHORES_PRIORITY == TRUE) case CH_STATE_WTSEM: #endif #if (CH_CFG_USE_MESSAGES == TRUE) && (CH_CFG_USE_MESSAGES_PRIORITY == TRUE) case CH_STATE_SNDMSGQ: #endif /* Re-enqueues tp with its new priority on the queue.*/ queue_prio_insert(queue_dequeue(tp), &tp->p_u.wtmtxp->m_queue); break; #endif case CH_STATE_READY: #if CH_DBG_ENABLE_ASSERTS == TRUE /* Prevents an assertion in chSchReadyI().*/ tp->p_state = CH_STATE_CURRENT; #endif /* Re-enqueues tp with its new priority on the ready list.*/ (void) chSchReadyI(queue_dequeue(tp)); break; default: /* Nothing to do for other states.*/ break; } break; } /* Sleep on the mutex.*/ queue_prio_insert(ctp, &mp->m_queue); ctp->p_u.wtmtxp = mp; chSchGoSleepS(CH_STATE_WTMTX); /* It is assumed that the thread performing the unlock operation assigns the mutex to this thread.*/ chDbgAssert(mp->m_owner == ctp, "not owner"); chDbgAssert(ctp->p_mtxlist == mp, "not owned"); #if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE chDbgAssert(mp->m_cnt == (cnt_t)1, "counter is not one"); } #endif } else { #if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE chDbgAssert(mp->m_cnt == (cnt_t)0, "counter is not zero"); mp->m_cnt++; #endif /* It was not owned, inserted in the owned mutexes list.*/ mp->m_owner = ctp; mp->m_next = ctp->p_mtxlist; ctp->p_mtxlist = mp; } }
/** * @brief Locks the specified mutex. * @post The mutex is locked and inserted in the per-thread stack of owned * mutexes. * * @param[in] mp pointer to the @p Mutex structure * * @sclass */ void chMtxLockS(Mutex *mp) { Thread *ctp = currp; chDbgCheckClassS(); chDbgCheck(mp != NULL, "chMtxLockS"); /* Is the mutex already locked? */ if (mp->m_owner != NULL) { /* Priority inheritance protocol; explores the thread-mutex dependencies boosting the priority of all the affected threads to equal the priority of the running thread requesting the mutex.*/ Thread *tp = mp->m_owner; /* Does the running thread have higher priority than the mutex owning thread? */ while (tp->p_prio < ctp->p_prio) { /* Make priority of thread tp match the running thread's priority.*/ tp->p_prio = ctp->p_prio; /* The following states need priority queues reordering.*/ switch (tp->p_state) { case THD_STATE_WTMTX: /* Re-enqueues the mutex owner with its 0; // new priority.*/ prio_insert(dequeue(tp), (ThreadsQueue *)tp->p_u.wtobjp); tp = ((Mutex *)tp->p_u.wtobjp)->m_owner; continue; #if CH_USE_CONDVARS | \ (CH_USE_SEMAPHORES && CH_USE_SEMAPHORES_PRIORITY) | \ (CH_USE_MESSAGES && CH_USE_MESSAGES_PRIORITY) #if CH_USE_CONDVARS case THD_STATE_WTCOND: #endif #if CH_USE_SEMAPHORES && CH_USE_SEMAPHORES_PRIORITY case THD_STATE_WTSEM: #endif #if CH_USE_MESSAGES && CH_USE_MESSAGES_PRIORITY case THD_STATE_SNDMSGQ: #endif /* Re-enqueues tp with its 0; // new priority on the queue.*/ prio_insert(dequeue(tp), (ThreadsQueue *)tp->p_u.wtobjp); break; #endif case THD_STATE_READY: #if CH_DBG_ENABLE_ASSERTS /* Prevents an assertion in chSchReadyI().*/ tp->p_state = THD_STATE_CURRENT; #endif /* Re-enqueues tp with its 0; // new priority on the ready list.*/ chSchReadyI(dequeue(tp)); break; } break; } /* Sleep on the mutex.*/ prio_insert(ctp, &mp->m_queue); ctp->p_u.wtobjp = mp; chSchGoSleepS(THD_STATE_WTMTX); /* It is assumed that the thread performing the unlock operation assigns the mutex to this thread.*/ chDbgAssert(mp->m_owner == ctp, "chMtxLockS(), #1", "not owner"); chDbgAssert(ctp->p_mtxlist == mp, "chMtxLockS(), #2", "not owned"); } else { /* It was not owned, inserted in the owned mutexes list.*/ mp->m_owner = ctp; mp->m_next = ctp->p_mtxlist; ctp->p_mtxlist = mp; } }
/** * @brief Puts the current thread to sleep into the specified state with * timeout specification. * @details The thread goes into a sleeping state, if it is not awakened * explicitly within the specified system time then it is forcibly * awakened with a @p NIL_MSG_TMO low level message. * * @param[in] newstate the new thread state or a semaphore pointer * @param[in] timeout the number of ticks before the operation timeouts. * the following special values are allowed: * - @a TIME_INFINITE no timeout. * . * @return The wakeup message. * @retval NIL_MSG_TMO if a timeout occurred. * * @sclass */ msg_t chSchGoSleepTimeoutS(tstate_t newstate, systime_t timeout) { thread_t *ntp, *otp = nil.current; chDbgCheckClassS(); chDbgAssert(otp != &nil.threads[CH_CFG_NUM_THREADS], "idle cannot sleep"); /* Storing the wait object for the current thread.*/ otp->state = newstate; #if CH_CFG_ST_TIMEDELTA > 0 if (timeout != TIME_INFINITE) { systime_t abstime; /* TIMEDELTA makes sure to have enough time to reprogram the timer before the free-running timer counter reaches the selected timeout.*/ if (timeout < (systime_t)CH_CFG_ST_TIMEDELTA) { timeout = (systime_t)CH_CFG_ST_TIMEDELTA; } /* Absolute time of the timeout event.*/ abstime = chVTGetSystemTimeX() + timeout; if (nil.lasttime == nil.nexttime) { /* Special case, first thread asking for a timeout.*/ port_timer_start_alarm(abstime); nil.nexttime = abstime; } else { /* Special case, there are already other threads with a timeout activated, evaluating the order.*/ if (chVTIsTimeWithinX(abstime, nil.lasttime, nil.nexttime)) { port_timer_set_alarm(abstime); nil.nexttime = abstime; } } /* Timeout settings.*/ otp->timeout = abstime - nil.lasttime; } #else /* Timeout settings.*/ otp->timeout = timeout; #endif /* Scanning the whole threads array.*/ ntp = nil.threads; while (true) { /* Is this thread ready to execute?*/ if (NIL_THD_IS_READY(ntp)) { nil.current = nil.next = ntp; if (ntp == &nil.threads[CH_CFG_NUM_THREADS]) { CH_CFG_IDLE_ENTER_HOOK(); } port_switch(ntp, otp); return nil.current->u1.msg; } /* Points to the next thread in lowering priority order.*/ ntp++; chDbgAssert(ntp <= &nil.threads[CH_CFG_NUM_THREADS], "pointer out of range"); } }