Priority inheritance: When CONFIG_SEM_PREALLOCHOLDERS==0, there is only a single, hard-allocated holder structure. This is problem because in sem_wait() the holder is released, but needs to remain in the holder container until sem_restorebaseprio() is called. The call to sem_restorebaseprio() must be one of the last things the sem_wait() does because it can cause the task to be suspended. If in sem_wait(), a new task gets the semaphore count then it will fail to allocate the holder and will not participate in priority inheritance. This fix is to add two hard-allocated holders in the sem_t structure: One of the old holder and one for the new holder.

This commit is contained in:
Gregory Nutt 2017-03-10 09:30:15 -06:00
parent 769427ed5a
commit 360539afac
3 changed files with 68 additions and 28 deletions

View File

@ -93,7 +93,7 @@ struct sem_s
# if CONFIG_SEM_PREALLOCHOLDERS > 0
FAR struct semholder_s *hhead; /* List of holders of semaphore counts */
# else
struct semholder_s holder; /* Single holder */
struct semholder_s holder[2]; /* Slot for old and new holder */
# endif
#endif
};
@ -104,12 +104,15 @@ typedef struct sem_s sem_t;
#ifdef CONFIG_PRIORITY_INHERITANCE
# if CONFIG_SEM_PREALLOCHOLDERS > 0
# define SEM_INITIALIZER(c) {(c), 0, NULL} /* semcount, flags, hhead */
# define SEM_INITIALIZER(c) \
{(c), 0, NULL} /* semcount, flags, hhead */
# else
# define SEM_INITIALIZER(c) {(c), 0, SEMHOLDER_INITIALIZER} /* semcount, flags, holder */
# define SEM_INITIALIZER(c) \
{(c), 0, SEMHOLDER_INITIALIZER, SEMHOLDER_INITIALIZER} /* semcount, flags, holder[2] */
# endif
#else
# define SEM_INITIALIZER(c) {(c)} /* semcount */
# define SEM_INITIALIZER(c) \
{(c)} /* semcount */
#endif
/****************************************************************************

View File

@ -83,17 +83,19 @@ int sem_init(FAR sem_t *sem, int pshared, unsigned int value)
{
/* Initialize the seamphore count */
sem->semcount = (int16_t)value;
sem->semcount = (int16_t)value;
/* Initialize to support priority inheritance */
#ifdef CONFIG_PRIORITY_INHERITANCE
sem->flags = 0;
sem->flags = 0;
# if CONFIG_SEM_PREALLOCHOLDERS > 0
sem->hhead = NULL;
sem->hhead = NULL;
# else
sem->holder.htcb = NULL;
sem->holder.counts = 0;
sem->holder[0].htcb = NULL;
sem->holder[0].counts = 0;
sem->holder[1].htcb = NULL;
sem->holder[1].counts = 0;
# endif
#endif
return OK;

View File

@ -108,16 +108,21 @@ static inline FAR struct semholder_s *sem_allocholder(sem_t *sem)
pholder->counts = 0;
}
#else
if (sem->holder.htcb == NULL)
if (sem->holder[0].htcb == NULL)
{
pholder = &sem->holder;
pholder = &sem->holder[0];
pholder->counts = 0;
}
else if (sem->holder[1].htcb == NULL)
{
pholder = &sem->holder[1];
pholder->counts = 0;
}
#endif
else
{
serr("ERROR: Insufficient pre-allocated holders\n");
pholder = NULL;
pholder = NULL;
}
return pholder;
@ -132,15 +137,12 @@ static FAR struct semholder_s *sem_findholder(sem_t *sem,
{
FAR struct semholder_s *pholder;
#if CONFIG_SEM_PREALLOCHOLDERS > 0
/* 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
for (pholder = sem->hhead; pholder != NULL; pholder = pholder->flink)
{
if (pholder->htcb == htcb)
{
@ -149,6 +151,22 @@ static FAR struct semholder_s *sem_findholder(sem_t *sem,
return pholder;
}
}
#else
int i;
/* We have two hard-allocated holder structuse in sem_t */
for (i = 0; i < 2; i++)
{
pholder = &sem->pholder[i];
if (pholder->htcb == htcb)
{
/* Got it! */
return pholder;
}
}
#endif
/* The holder does not appear in the list */
@ -223,23 +241,20 @@ 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
FAR struct semholder_s *next;
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 */
/* Check if there is a handler... there should always be one
* in this configuration.
*/
if (pholder->htcb != NULL)
{
@ -248,6 +263,25 @@ static int sem_foreachholder(FAR sem_t *sem, holderhandler_t handler,
ret = handler(pholder, sem, arg);
}
}
#else
int i;
/* We have two hard-allocated holder structures in sem_t */
for (i = 0; i < 2; i++)
{
pholder = &sem->holder[i];
/* The hard-allocated containers may hold a NULL holder */
if (pholder->htcb != NULL)
{
/* Call the handler */
ret = handler(pholder, sem, arg);
}
}
#endif
return ret;
}
@ -823,12 +857,13 @@ void sem_destroyholder(FAR sem_t *sem)
(void)sem_foreachholder(sem, sem_recoverholders, NULL);
}
#else
if (sem->holder.htcb != NULL)
if (sem->holder[0].htcb != NULL || sem->holder[0].htcb != NULL)
{
serr("ERROR: Semaphore destroyed with holder\n");
}
sem->holder.htcb = NULL;
sem->holder[0].htcb = NULL;
sem->holder[1].htcb = NULL;
#endif
}