/** * @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 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(); }
/** * @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; }
/** * @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. * * @return A pointer to the unlocked mutex. * * @api */ Mutex *chMtxUnlock(void) { Thread *ctp = currp; Mutex *ump, *mp; chSysLock(); chDbgAssert(ctp->p_mtxlist != NULL, "chMtxUnlock(), #1", "owned mutexes list empty"); chDbgAssert(ctp->p_mtxlist->m_owner == ctp, "chMtxUnlock(), #2", "ownership failure"); /* Removes the top Mutex from the Thread's 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; } /* 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.*/ tp = fifo_remove(&ump->m_queue); ump->m_owner = tp; ump->m_next = tp->p_mtxlist; tp->p_mtxlist = ump; chSchWakeupS(tp, RDY_OK); } else ump->m_owner = NULL; chSysUnlock(); return ump; }
/** * @brief Unlocks all the 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 *ctp = currp; chSysLock(); if (ctp->p_mtxlist != NULL) { do { Mutex *ump = ctp->p_mtxlist; ctp->p_mtxlist = ump->m_next; if (chMtxQueueNotEmptyS(ump)) { Thread *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; } while (ctp->p_mtxlist != NULL); ctp->p_prio = ctp->p_realprio; chSchRescheduleS(); } chSysUnlock(); }
/** * @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(); }