diff options
Diffstat (limited to 'nuttx/sched/sem_holder.c')
-rw-r--r-- | nuttx/sched/sem_holder.c | 1055 |
1 files changed, 0 insertions, 1055 deletions
diff --git a/nuttx/sched/sem_holder.c b/nuttx/sched/sem_holder.c deleted file mode 100644 index 1bae37746..000000000 --- a/nuttx/sched/sem_holder.c +++ /dev/null @@ -1,1055 +0,0 @@ -/**************************************************************************** - * sched/sem_holder.c - * - * Copyright (C) 2009-2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt <gnutt@nuttx.org> - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include <nuttx/config.h> - -#include <semaphore.h> -#include <sched.h> -#include <assert.h> -#include <debug.h> -#include <nuttx/arch.h> - -#include "os_internal.h" -#include "sem_internal.h" - -#ifdef CONFIG_PRIORITY_INHERITANCE - -/**************************************************************************** - * Definitions - ****************************************************************************/ - -/* Configuration ************************************************************/ - -#ifndef CONFIG_SEM_PREALLOCHOLDERS -# define CONFIG_SEM_PREALLOCHOLDERS 0 -#endif - -/**************************************************************************** - * Private Type Declarations - ****************************************************************************/ - -typedef int (*holderhandler_t)(FAR struct semholder_s *pholder, - FAR sem_t *sem, FAR void *arg); - -/**************************************************************************** - * Global Variables - ****************************************************************************/ - -/**************************************************************************** - * Private Variables - ****************************************************************************/ - -/* Preallocated holder structures */ - -#if CONFIG_SEM_PREALLOCHOLDERS > 0 -static struct semholder_s g_holderalloc[CONFIG_SEM_PREALLOCHOLDERS]; -static FAR struct semholder_s *g_freeholders; -#endif - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: sem_allocholder - ****************************************************************************/ - -static inline FAR struct semholder_s *sem_allocholder(sem_t *sem) -{ - FAR struct semholder_s *pholder; - - /* Check if the "built-in" holder is being used. We have this built-in - * holder to optimize for the simplest case where semaphores are only - * used to implement mutexes. - */ - -#if CONFIG_SEM_PREALLOCHOLDERS > 0 - pholder = g_freeholders; - if (pholder) - { - /* Remove the holder from the free list an put it into the semaphore's holder list */ - - g_freeholders = pholder->flink; - pholder->flink = sem->hhead; - sem->hhead = pholder; - - /* Make sure the initial count is zero */ - - pholder->counts = 0; - } -#else - if (!sem->holder.htcb) - { - pholder = &sem->holder; - pholder->counts = 0; - } -#endif - else - { - sdbg("Insufficient pre-allocated holders\n"); - pholder = NULL; - } - - return pholder; -} - -/**************************************************************************** - * Name: sem_findholder - ****************************************************************************/ - -static FAR struct semholder_s *sem_findholder(sem_t *sem, FAR _TCB *htcb) -{ - FAR struct semholder_s *pholder; - - /* Try to find the holder in the list of holders associated with this semaphore */ - -#if CONFIG_SEM_PREALLOCHOLDERS > 0 - for (pholder = sem->hhead; pholder; pholder = pholder->flink) -#else - pholder = &sem->holder; -#endif - { - if (pholder->htcb == htcb) - { - /* Got it! */ - - return pholder; - } - } - - /* The holder does not appear in the list */ - - return NULL; -} - -/**************************************************************************** - * Name: sem_findorallocateholder - ****************************************************************************/ - -static inline FAR struct semholder_s *sem_findorallocateholder(sem_t *sem, FAR _TCB *htcb) -{ - FAR struct semholder_s *pholder = sem_findholder(sem, htcb); - if (!pholder) - { - pholder = sem_allocholder(sem); - } - - return pholder; -} - -/**************************************************************************** - * Name: sem_freeholder - ****************************************************************************/ - -static inline void sem_freeholder(sem_t *sem, FAR struct semholder_s *pholder) -{ -#if CONFIG_SEM_PREALLOCHOLDERS > 0 - FAR struct semholder_s *curr; - FAR struct semholder_s *prev; -#endif - - /* Release the holder and counts */ - - pholder->htcb = NULL; - pholder->counts = 0; - -#if CONFIG_SEM_PREALLOCHOLDERS > 0 - /* Search the list for the matching holder */ - - for (prev = NULL, curr = sem->hhead; - curr && curr != pholder; - prev = curr, curr = curr->flink); - - if (curr) - { - /* Remove the holder from the list */ - - if (prev) - { - prev->flink = pholder->flink; - } - else - { - sem->hhead = pholder->flink; - } - - /* And put it in the free list */ - - pholder->flink = g_freeholders; - g_freeholders = pholder; - } -#endif -} - -/**************************************************************************** - * Name: sem_foreachholder - ****************************************************************************/ - -static int sem_foreachholder(FAR sem_t *sem, holderhandler_t handler, FAR void *arg) -{ - FAR struct semholder_s *pholder; -#if CONFIG_SEM_PREALLOCHOLDERS > 0 - FAR struct semholder_s *next; -#endif - int ret = 0; - -#if CONFIG_SEM_PREALLOCHOLDERS > 0 - for (pholder = sem->hhead; pholder && ret == 0; pholder = next) -#else - pholder = &sem->holder; -#endif - { -#if CONFIG_SEM_PREALLOCHOLDERS > 0 - /* In case this holder gets deleted */ - - next = pholder->flink; -#endif - /* The initial "built-in" container may hold a NULL holder */ - - if (pholder->htcb) - { - /* Call the handler */ - - ret = handler(pholder, sem, arg); - } - } - - return ret; -} - -/**************************************************************************** - * Name: sem_recoverholders - ****************************************************************************/ - -#if CONFIG_SEM_PREALLOCHOLDERS > 0 -static int sem_recoverholders(FAR struct semholder_s *pholder, FAR sem_t *sem, FAR void *arg) -{ - sem_freeholder(sem, pholder); - return 0; -} -#endif - -/**************************************************************************** - * Name: sem_boostholderprio - ****************************************************************************/ - -static int sem_boostholderprio(FAR struct semholder_s *pholder, - FAR sem_t *sem, FAR void *arg) -{ - FAR _TCB *htcb = (FAR _TCB *)pholder->htcb; - FAR _TCB *rtcb = (FAR _TCB*)arg; - - /* Make sure that the holder thread is still active. If it exited without - * releasing its counts, then that would be a bad thing. But we can take no - * real action because we don't know know that the program is doing. Perhaps - * its plan is to kill a thread, then destroy the semaphore. - */ - - if (!sched_verifytcb(htcb)) - { - sdbg("TCB 0x%08x is a stale handle, counts lost\n", htcb); - sem_freeholder(sem, pholder); - } - -#if CONFIG_SEM_NNESTPRIO > 0 - - /* If the priority of the thread that is waiting for a count is greater than - * the base priority of the thread holding a count, then we may need to - * adjust the holder's priority now or later to that priority. - */ - - else if (rtcb->sched_priority > htcb->base_priority) - { - /* If the new priority is greater than the current, possibly already - * boosted priority of the holder thread, then we will have to raise - * the holder's priority now. - */ - - if (rtcb->sched_priority > htcb->sched_priority) - { - /* If the current priority of holder thread has already been - * boosted, then add the boost priority to the list of restoration - * priorities. When the higher priority waiter thread gets its - * count, then we need to revert the holder thread to this saved - * priority (not to its base priority). - */ - - if (htcb->sched_priority > htcb->base_priority) - { - /* Save the current, boosted priority of the holder thread. */ - - if (htcb->npend_reprio < CONFIG_SEM_NNESTPRIO) - { - htcb->pend_reprios[htcb->npend_reprio] = htcb->sched_priority; - htcb->npend_reprio++; - } - else - { - sdbg("CONFIG_SEM_NNESTPRIO exceeded\n"); - } - } - - /* Raise the priority of the thread holding of the semaphore. - * This cannot cause a context switch because we have preemption - * disabled. The holder thread may be marked "pending" and the - * switch may occur during up_block_task() processing. - */ - - (void)sched_setpriority(htcb, rtcb->sched_priority); - } - else - { - /* The new priority is above the base priority of the holder, - * but not as high as its current working priority. Just put it - * in the list of pending restoration priorities so that when the - * higher priority thread gets its count, we can revert to this - * saved priority and not to the base priority. - */ - - htcb->pend_reprios[htcb->npend_reprio] = rtcb->sched_priority; - htcb->npend_reprio++; - } - } - -#else - /* If the priority of the thread that is waiting for a count is less than - * of equal to the priority of the thread holding a count, then do nothing - * because the thread is already running at a sufficient priority. - */ - - else if (rtcb->sched_priority > htcb->sched_priority) - { - /* Raise the priority of the holder of the semaphore. This - * cannot cause a context switch because we have preemption - * disabled. The task will be marked "pending" and the switch - * will occur during up_block_task() processing. - */ - - (void)sched_setpriority(htcb, rtcb->sched_priority); - } -#endif - - return 0; -} - -/**************************************************************************** - * Name: sem_verifyholder - ****************************************************************************/ - -#ifdef CONFIG_DEBUG -static int sem_verifyholder(FAR struct semholder_s *pholder, FAR sem_t *sem, FAR void *arg) -{ -#if 0 // Need to revisit this, but these assumptions seem to be untrue -- OR there is a bug??? - FAR _TCB *htcb = (FAR _TCB *)pholder->htcb; - - /* Called after a semaphore has been released (incremented), the semaphore - * could is non-negative, and there is no thread waiting for the count. - * In this case, the priority of the holder should not be boosted. - */ - -#if CONFIG_SEM_NNESTPRIO > 0 - DEBUGASSERT(htcb->npend_reprio == 0); -#endif - DEBUGASSERT(htcb->sched_priority == htcb->base_priority); -#endif - return 0; -} -#endif - -/**************************************************************************** - * Name: sem_dumpholder - ****************************************************************************/ - -#if defined(CONFIG_DEBUG) && defined(CONFIG_SEM_PHDEBUG) -static int sem_dumpholder(FAR struct semholder_s *pholder, FAR sem_t *sem, FAR void *arg) -{ -#if CONFIG_SEM_PREALLOCHOLDERS > 0 - dbg(" %08x: %08x %08x %04x\n", - pholder, pholder->flink, pholder->htcb, pholder->counts); -#else - dbg(" %08x: %08x %04x\n", pholder, pholder->htcb, pholder->counts); -#endif - return 0; -} -#endif - -/**************************************************************************** - * Name: sem_restoreholderprio - ****************************************************************************/ - -static int sem_restoreholderprio(FAR struct semholder_s *pholder, FAR sem_t *sem, FAR void *arg) -{ - FAR _TCB *htcb = (FAR _TCB *)pholder->htcb; -#if CONFIG_SEM_NNESTPRIO > 0 - FAR _TCB *stcb = (FAR _TCB *)arg; - int rpriority; - int i; - int j; -#endif - - /* Make sure that the hdoler thread is still active. If it exited without - * releasing its counts, then that would be a bad thing. But we can take no - * real action because we don't know know that the program is doing. Perhaps - * its plan is to kill a thread, then destroy the semaphore. - */ - - if (!sched_verifytcb(htcb)) - { - sdbg("TCB 0x%08x is a stale handle, counts lost\n", htcb); - sem_freeholder(sem, pholder); - } - - /* Was the priority of the holder thread boosted? If so, then drop its - * priority back to the correct level. What is the correct level? - */ - - else if (htcb->sched_priority != htcb->base_priority) - { -#if CONFIG_SEM_NNESTPRIO > 0 - /* Are there other, pending priority levels to revert to? */ - - if (htcb->npend_reprio < 1) - { - /* No... the holder thread has only been boosted once. Reset all - * priorities back to the base priority. - */ - - //DEBUGASSERT(htcb->sched_priority == stcb->sched_priority && htcb->npend_reprio == 0); - sched_reprioritize(htcb, htcb->base_priority); - } - - /* There are multiple pending priority levels. The holder thread's "boosted" - * priority could greater than or equal to "stcb->sched_priority" (it could be - * greater if its priority we boosted becuase it also holds another semaphore). - */ - - else if (htcb->sched_priority <= stcb->sched_priority) - { - /* The holder thread has been boosted to the same priority as the waiter - * thread that just received the count. We will simply reprioritize - * to the next highest priority that we have in rpriority. - */ - - /* Find the highest pending priority and remove it from the list */ - - for (i = 1, j = 0; i < htcb->npend_reprio; i++) - { - if (htcb->pend_reprios[i] > htcb->pend_reprios[j]) - { - j = i; - } - } - - /* Remove the highest priority pending priority from the list */ - - rpriority = htcb->pend_reprios[j]; - i = htcb->npend_reprio - 1; - if (i > 0) - { - htcb->pend_reprios[j] = htcb->pend_reprios[i]; - } - - htcb->npend_reprio = i; - - /* And apply that priority to the thread (while retaining the base_priority) */ - - sched_setpriority(htcb, rpriority); - } - else - { - /* The holder thread has been boosted to a higher priority than the - * waiter task. The pending priority should be in the list (unless it - * was lost because of of list overflow or because the holder was - * reporioritize again unbeknownst to the priority inheritance logic). - * - * Search the list for the matching priority. - */ - - for (i = 0; i < htcb->npend_reprio; i++) - { - /* Does this pending priority match the priority of the thread - * that just received the count? - */ - - if (htcb->pend_reprios[i] == stcb->sched_priority) - { - /* Yes, remove it from the list */ - - j = htcb->npend_reprio - 1; - if (j > 0) - { - htcb->pend_reprios[i] = htcb->pend_reprios[j]; - } - - htcb->npend_reprio = j; - break; - } - } - } -#else - /* There is no alternative restore priorities, drop the priority - * of the holder thread all the way back to the threads "base" - * priority. - */ - - sched_reprioritize(htcb, htcb->base_priority); -#endif - } - - return 0; -} - -/**************************************************************************** - * Name: sem_restoreholderprioA - * - * Description: - * Reprioritize all holders except the currently executing task - * - ****************************************************************************/ - -static int sem_restoreholderprioA(FAR struct semholder_s *pholder, - FAR sem_t *sem, FAR void *arg) -{ - FAR _TCB *rtcb = (FAR _TCB*)g_readytorun.head; - if (pholder->htcb != rtcb) - { - return sem_restoreholderprio(pholder, sem, arg); - } - - return 0; -} - -/**************************************************************************** - * Name: sem_restoreholderprioB - * - * Description: - * Reprioritize only the currently executing task - * - ****************************************************************************/ - -static int sem_restoreholderprioB(FAR struct semholder_s *pholder, - FAR sem_t *sem, FAR void *arg) -{ - FAR _TCB *rtcb = (FAR _TCB*)g_readytorun.head; - if (pholder->htcb == rtcb) - { - (void)sem_restoreholderprio(pholder, sem, arg); - return 1; - } - - return 0; -} - -/**************************************************************************** - * Name: sem_restorebaseprio_irq - * - * Description: - * This function is called after the an interrupt handler posts a count on - * the semaphore. It will check if we need to drop the priority of any - * threads holding a count on the semaphore. Their priority could have - * been boosted while they held the count. - * - * Parameters: - * stcb - The TCB of the task that was just started (if any). If the - * post action caused a count to be given to another thread, then stcb - * is the TCB that received the count. Note, just because stcb received - * the count, it does not mean that it it is higher priority than other - * threads. - * sem - A reference to the semaphore being posted. - * - If the semaphore count is <0 then there are still threads waiting - * for a count. stcb should be non-null and will be higher priority - * than all of the other threads still waiting. - * - If it is ==0 then stcb refers to the thread that got the last count; - * no other threads are waiting. - * - If it is >0 then there should be no threads waiting for counts and - * stcb should be null. - * - * Return Value: - * None - * - * Assumptions: - * The scheduler is locked. - * - ****************************************************************************/ - -static inline void sem_restorebaseprio_irq(FAR _TCB *stcb, FAR sem_t *sem) -{ - /* Perfom the following actions only if a new thread was given a count. - * The thread that received the count should be the highest priority - * of all threads waiting for a count from the semphore. So in that - * case, the priority of all holder threads should be dropped to the - * next highest pending priority. - */ - - if (stcb) - { - /* Drop the priority of all holder threads */ - - (void)sem_foreachholder(sem, sem_restoreholderprio, stcb); - } - - /* If there are no tasks waiting for available counts, then all holders - * should be at their base priority. - */ - -#ifdef CONFIG_DEBUG - else - { - (void)sem_foreachholder(sem, sem_verifyholder, NULL); - } -#endif -} - -/**************************************************************************** - * Name: sem_restorebaseprio_task - * - * Description: - * This function is called after the current running task releases a - * count on the semaphore. It will check if we need to drop the priority - * of any threads holding a count on the semaphore. Their priority could - * have been boosted while they held the count. - * - * Parameters: - * stcb - The TCB of the task that was just started (if any). If the - * post action caused a count to be given to another thread, then stcb - * is the TCB that received the count. Note, just because stcb received - * the count, it does not mean that it it is higher priority than other - * threads. - * sem - A reference to the semaphore being posted. - * - If the semaphore count is <0 then there are still threads waiting - * for a count. stcb should be non-null and will be higher priority - * than all of the other threads still waiting. - * - If it is ==0 then stcb refers to the thread that got the last count; - * no other threads are waiting. - * - If it is >0 then there should be no threads waiting for counts and - * stcb should be null. - * - * Return Value: - * None - * - * Assumptions: - * The scheduler is locked. - * - ****************************************************************************/ - -static inline void sem_restorebaseprio_task(FAR _TCB *stcb, FAR sem_t *sem) -{ - FAR _TCB *rtcb = (FAR _TCB*)g_readytorun.head; - FAR struct semholder_s *pholder; - - /* Perfom the following actions only if a new thread was given a count. - * The thread that received the count should be the highest priority - * of all threads waiting for a count from the semphore. So in that - * case, the priority of all holder threads should be dropped to the - * next highest pending priority. - */ - - if (stcb) - { - /* The currently executed thread should be the lower priority - * thread that just posted the count and caused this action. - * However, we cannot drop the priority of the currently running - * thread -- becuase that will cause it to be suspended. - * - * So, do this in two passes. First, reprioritizing all holders - * except for the running thread. - */ - - (void)sem_foreachholder(sem, sem_restoreholderprioA, stcb); - - /* Now, find an reprioritize only the ready to run task */ - - (void)sem_foreachholder(sem, sem_restoreholderprioB, stcb); - } - - /* If there are no tasks waiting for available counts, then all holders - * should be at their base priority. - */ - -#ifdef CONFIG_DEBUG - else - { - (void)sem_foreachholder(sem, sem_verifyholder, NULL); - } -#endif - - /* In any case, the currently executing task should have an entry in the - * list. Its counts were previously decremented; if it now holds no - * counts, then we need to remove it from the list of holders. - */ - - pholder = sem_findholder(sem, rtcb); - if (pholder) - { - /* When no more counts are held, remove the holder from the list. The - * count was decremented in sem_releaseholder. - */ - - if (pholder->counts <= 0) - { - sem_freeholder(sem, pholder); - } - } -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: sem_initholders - * - * Description: - * Called from sem_initialize() to set up semaphore holder information. - * - * Parameters: - * None - * - * Return Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -void sem_initholders(void) -{ -#if CONFIG_SEM_PREALLOCHOLDERS > 0 - int i; - - /* Put all of the pre-allocated holder structures into free list */ - - g_freeholders = g_holderalloc; - for (i = 0; i < (CONFIG_SEM_PREALLOCHOLDERS-1); i++) - { - g_holderalloc[i].flink = &g_holderalloc[i+1]; - } - - g_holderalloc[CONFIG_SEM_PREALLOCHOLDERS-1].flink = NULL; -#endif -} - -/**************************************************************************** - * Name: sem_destroyholder - * - * Description: - * Called from sem_destroy() to handle any holders of a semaphore when - * it is destroyed. - * - * Parameters: - * sem - A reference to the semaphore being destroyed - * - * Return Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -void sem_destroyholder(FAR sem_t *sem) -{ - /* It is an error if a semaphore is destroyed while there are any holders - * (except perhaps the thread release the semaphore itself). Hmmm.. but - * we actually have to assume that the caller knows what it is doing because - * could have killed another thread that is the actual holder of the semaphore. - * We cannot make any assumptions about the state of the semaphore or the - * state of any of the holder threads. - * - * So just recover any stranded holders and hope the task knows what it is - * doing. - */ - -#if CONFIG_SEM_PREALLOCHOLDERS > 0 - if (sem->hhead) - { - sdbg("Semaphore destroyed with holders\n"); - (void)sem_foreachholder(sem, sem_recoverholders, NULL); - } -#else - if (sem->holder.htcb) - { - sdbg("Semaphore destroyed with holder\n"); - } - - sem->holder.htcb = NULL; -#endif -} - -/**************************************************************************** - * Name: sem_addholder - * - * Description: - * Called from sem_wait() when the calling thread obtains the semaphore - * - * Parameters: - * sem - A reference to the incremented semaphore - * - * Return Value: - * 0 (OK) or -1 (ERROR) if unsuccessful - * - * Assumptions: - * - ****************************************************************************/ - -void sem_addholder(FAR sem_t *sem) -{ - FAR _TCB *rtcb = (FAR _TCB*)g_readytorun.head; - FAR struct semholder_s *pholder; - - /* Find or allocate a container for this new holder */ - - pholder = sem_findorallocateholder(sem, rtcb); - if (pholder) - { - /* Then set the holder and increment the number of counts held by this holder */ - - pholder->htcb = rtcb; - pholder->counts++; - } -} - -/**************************************************************************** - * Name: void sem_boostpriority(sem_t *sem) - * - * Description: - * - * - * Parameters: - * None - * - * Return Value: - * 0 (OK) or -1 (ERROR) if unsuccessful - * - * Assumptions: - * - ****************************************************************************/ - -void sem_boostpriority(FAR sem_t *sem) -{ - FAR _TCB *rtcb = (FAR _TCB*)g_readytorun.head; - - /* Boost the priority of every thread holding counts on this semaphore - * that are lower in priority than the new thread that is waiting for a - * count. - */ - - (void)sem_foreachholder(sem, sem_boostholderprio, rtcb); -} - -/**************************************************************************** - * Name: sem_releaseholder - * - * Description: - * Called from sem_post() after a thread releases one count on the - * semaphore. - * - * Parameters: - * sem - A reference to the semaphore being posted - * - * Return Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -void sem_releaseholder(FAR sem_t *sem) -{ - FAR _TCB *rtcb = (FAR _TCB*)g_readytorun.head; - FAR struct semholder_s *pholder; - - /* Find the container for this holder */ - - pholder = sem_findholder(sem, rtcb); - if (pholder && pholder->counts > 0) - { - /* Decrement the counts on this holder -- the holder will be freed - * later in sem_restorebaseprio. - */ - - pholder->counts--; - } -} - -/**************************************************************************** - * Name: sem_restorebaseprio - * - * Description: - * This function is called after the current running task releases a - * count on the semaphore or an interrupt handler posts a new count. It - * will check if we need to drop the priority of any threads holding a - * count on the semaphore. Their priority could have been boosted while - * they held the count. - * - * Parameters: - * stcb - The TCB of the task that was just started (if any). If the - * post action caused a count to be given to another thread, then stcb - * is the TCB that received the count. Note, just because stcb received - * the count, it does not mean that it it is higher priority than other - * threads. - * sem - A reference to the semaphore being posted. - * - If the semaphore count is <0 then there are still threads waiting - * for a count. stcb should be non-null and will be higher priority - * than all of the other threads still waiting. - * - If it is ==0 then stcb refers to the thread that got the last count; - * no other threads are waiting. - * - If it is >0 then there should be no threads waiting for counts and - * stcb should be null. - * - * Return Value: - * None - * - * Assumptions: - * The scheduler is locked. - * - ****************************************************************************/ - -void sem_restorebaseprio(FAR _TCB *stcb, FAR sem_t *sem) -{ - /* Check our assumptions */ - - DEBUGASSERT((sem->semcount > 0 && stcb == NULL) || - (sem->semcount <= 0 && stcb != NULL)); - - /* Handler semaphore counts posed from an interrupt handler differently - * from interrupts posted from threads. The primary difference is that - * if the semaphore is posted from a thread, then the poster thread is - * a player in the priority inheritance scheme. The interrupt handler - * externally injects the new count without otherwise participating - * itself. - */ - - if (up_interrupt_context()) - { - sem_restorebaseprio_irq(stcb, sem); - } - else - { - sem_restorebaseprio_task(stcb, sem); - } -} - -/**************************************************************************** - * Name: sem_canceled - * - * Description: - * Called from sem_waitirq() after a thread that was waiting for a semaphore - * count was awakened because of a signal and the semaphore wait has been - * canceled. This function restores the correct thread priority of each - * holder of the semaphore. - * - * Parameters: - * sem - A reference to the semaphore no longer being waited for - * - * Return Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#ifndef CONFIG_DISABLE_SIGNALS -void sem_canceled(FAR _TCB *stcb, FAR sem_t *sem) -{ - /* Check our assumptions */ - - DEBUGASSERT(sem->semcount <= 0); - - /* Adjust the priority of every holder as necessary */ - - (void)sem_foreachholder(sem, sem_restoreholderprio, stcb); -} -#endif - -/**************************************************************************** - * Name: sem_enumholders - * - * Description: - * Show information about threads currently waiting on this semaphore - * - * Parameters: - * sem - A reference to the semaphore - * - * Return Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#if defined(CONFIG_DEBUG) && defined(CONFIG_SEM_PHDEBUG) -void sem_enumholders(FAR sem_t *sem) -{ - (void)sem_foreachholder(sem, sem_dumpholder, NULL); -} -#endif - -/**************************************************************************** - * Name: sem_nfreeholders - * - * Description: - * Return the number of available holder containers. This is a good way - * to find out which threads are not calling sem_destroy. - * - * Parameters: - * sem - A reference to the semaphore - * - * Return Value: - * The number of available holder containers - * - * Assumptions: - * - ****************************************************************************/ - -#if defined(CONFIG_DEBUG) && defined(CONFIG_SEM_PHDEBUG) -int sem_nfreeholders(void) -{ -#if CONFIG_SEM_PREALLOCHOLDERS > 0 - FAR struct semholder_s *pholder; - int n; - - for (pholder = g_freeholders, n = 0; pholder; pholder = pholder->flink) n++; - return n; -#else - return 0; -#endif -} -#endif - -#endif /* CONFIG_PRIORITY_INHERITANCE */ |