Finishes initial verification of priority inheritance logic

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@1600 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo 2009-03-14 00:46:02 +00:00
parent e1412760e1
commit 06e367a9e2
2 changed files with 81 additions and 32 deletions

View File

@ -91,17 +91,17 @@ static int g_medpri;
static int g_lowpri; static int g_lowpri;
/**************************************************************************** /****************************************************************************
* Name: nhighpri_started * Name: nhighpri_waiting
****************************************************************************/ ****************************************************************************/
static int nhighpri_started(void) static int nhighpri_waiting(void)
{ {
int n = 0; int n = 0;
int i; int i;
for (i = 0; i < NHIGHPRI_THREADS; i++) for (i = 0; i < NHIGHPRI_THREADS; i++)
{ {
if (g_highstate[i] != NOTSTARTED) if (g_highstate[i] == WAITING)
{ {
n++; n++;
} }
@ -137,9 +137,13 @@ static void *highpri_thread(void *parameter)
int threadno = (int)parameter; int threadno = (int)parameter;
int ret; int ret;
g_highstate[threadno-1] = RUNNING;
printf("highpri_thread-%d: Started\n", threadno); printf("highpri_thread-%d: Started\n", threadno);
fflush(stdout); fflush(stdout);
sleep(1);
printf("highpri_thread-%d: Calling sem_wait()\n", threadno);
g_highstate[threadno-1] = WAITING; g_highstate[threadno-1] = WAITING;
ret = sem_wait(&g_sem); ret = sem_wait(&g_sem);
g_highstate[threadno-1] = DONE; g_highstate[threadno-1] = DONE;
@ -230,7 +234,7 @@ static void *lowpri_thread(void *parameter)
int count; int count;
int policy; int policy;
int ret; int ret;
int nrunning; int nwaiting;
int i; int i;
g_lowstate[threadno-1] = RUNNING; g_lowstate[threadno-1] = RUNNING;
@ -260,7 +264,7 @@ static void *lowpri_thread(void *parameter)
{ {
/* Hang on to the thread until the middle priority thread runs */ /* Hang on to the thread until the middle priority thread runs */
while (g_middlestate == NOTSTARTED && nhighpri_started() < NHIGHPRI_THREADS) while (g_middlestate == NOTSTARTED && nhighpri_waiting() < NHIGHPRI_THREADS)
{ {
printf("lowpri_thread-%d: Waiting for the midle pri task to run\n", threadno); printf("lowpri_thread-%d: Waiting for the midle pri task to run\n", threadno);
printf(" g_middlestate: %d\n", (int)g_middlestate); printf(" g_middlestate: %d\n", (int)g_middlestate);
@ -280,18 +284,18 @@ static void *lowpri_thread(void *parameter)
sched_lock(); /* Needs to be atomic */ sched_lock(); /* Needs to be atomic */
ret = sem_getvalue(&g_sem, &count); ret = sem_getvalue(&g_sem, &count);
nrunning = nhighpri_running(); nwaiting = nhighpri_waiting();
sched_unlock(); sched_unlock();
if (ret < 0) if (ret < 0)
{ {
printf("lowpri_thread-%d: ERROR sem_getvalue failed: %d\n", threadno, errno); printf("lowpri_thread-%d: ERROR sem_getvalue failed: %d\n", threadno, errno);
} }
printf("lowpri_thread-%d: Sem count: %d, No. highpri thread: %d\n", threadno, count, nrunning); printf("lowpri_thread-%d: Sem count: %d, No. highpri thread: %d\n", threadno, count, nwaiting);
/* The middle priority task is running, let go of the semaphore */ /* The middle priority task is running, let go of the semaphore */
if (g_middlestate == RUNNING && nrunning == -count) if (g_middlestate == RUNNING && nwaiting == -count)
{ {
/* Good.. the middle priority task is still running and the counts are okay. */ /* Good.. the middle priority task is still running and the counts are okay. */
@ -299,7 +303,12 @@ static void *lowpri_thread(void *parameter)
} }
else else
{ {
printf("lowpri_thread-%d: ERROR the middle priority task has already exitted!\n", threadno); /* If the sem count is positive, then there all of the higher priority threads
* should have already completed.
*/
printf("lowpri_thread-%d: %s the middle priority task has already exitted!\n",
threadno, count >= 0 ? "SUCCESS" : "ERROR" );
printf(" g_middlestate: %d sem count=%d\n", (int)g_middlestate, count); printf(" g_middlestate: %d sem count=%d\n", (int)g_middlestate, count);
for (i = 0; i < NHIGHPRI_THREADS; i++) for (i = 0; i < NHIGHPRI_THREADS; i++)
{ {
@ -317,7 +326,7 @@ static void *lowpri_thread(void *parameter)
} }
else else
{ {
if (nhighpri_running() > 0) if (nwaiting > 0)
{ {
expected = g_highpri; expected = g_highpri;
} }
@ -478,7 +487,7 @@ void priority_inheritance(void)
printf("priority_inheritance: pthread_attr_init failed, status=%d\n", status); printf("priority_inheritance: pthread_attr_init failed, status=%d\n", status);
} }
sparam.sched_priority = g_highpri; sparam.sched_priority = g_highpri - i;
status = pthread_attr_setschedparam(&attr,& sparam); status = pthread_attr_setschedparam(&attr,& sparam);
if (status != OK) if (status != OK)
{ {
@ -502,7 +511,7 @@ void priority_inheritance(void)
/* Wait for all thread instances to complete */ /* Wait for all thread instances to complete */
for (i = 0; i < NLOWPRI_THREADS; i++) for (i = 0; i < NHIGHPRI_THREADS; i++)
{ {
printf("priority_inheritance: Waiting for highpri_thread-%d to complete\n", i+1); printf("priority_inheritance: Waiting for highpri_thread-%d to complete\n", i+1);
fflush(stdout); fflush(stdout);

View File

@ -63,7 +63,7 @@
* Private Type Declarations * Private Type Declarations
****************************************************************************/ ****************************************************************************/
typedef int (*holderhandler_t)(struct semholder_s *pholder, FAR sem_t *sem, FAR void *arg); typedef int (*holderhandler_t)(FAR struct semholder_s *pholder, FAR sem_t *sem, FAR void *arg);
/**************************************************************************** /****************************************************************************
* Global Variables * Global Variables
@ -217,9 +217,9 @@ static inline void sem_freeholder(sem_t *sem, FAR struct semholder_s *pholder)
static int sem_foreachholder(FAR sem_t *sem, holderhandler_t handler, FAR void *arg) static int sem_foreachholder(FAR sem_t *sem, holderhandler_t handler, FAR void *arg)
{ {
struct semholder_s *pholder = &sem->hlist; FAR struct semholder_s *pholder = &sem->hlist;
#if CONFIG_SEM_PREALLOCHOLDERS > 0 #if CONFIG_SEM_PREALLOCHOLDERS > 0
struct semholder_s *next; FAR struct semholder_s *next;
#endif #endif
int ret = 0; int ret = 0;
@ -248,7 +248,7 @@ static int sem_foreachholder(FAR sem_t *sem, holderhandler_t handler, FAR void *
* Name: sem_recoverholders * Name: sem_recoverholders
****************************************************************************/ ****************************************************************************/
static int sem_recoverholders(struct semholder_s *pholder, FAR sem_t *sem, FAR void *arg) static int sem_recoverholders(FAR struct semholder_s *pholder, FAR sem_t *sem, FAR void *arg)
{ {
sem_freeholder(sem, pholder); sem_freeholder(sem, pholder);
return 0; return 0;
@ -258,7 +258,7 @@ static int sem_recoverholders(struct semholder_s *pholder, FAR sem_t *sem, FAR v
* Name: sem_boostholderprio * Name: sem_boostholderprio
****************************************************************************/ ****************************************************************************/
static int sem_boostholderprio(struct semholder_s *pholder, FAR sem_t *sem, FAR void *arg) static int sem_boostholderprio(FAR struct semholder_s *pholder, FAR sem_t *sem, FAR void *arg)
{ {
FAR _TCB *htcb = (FAR _TCB *)pholder->holder; FAR _TCB *htcb = (FAR _TCB *)pholder->holder;
FAR _TCB *rtcb = (FAR _TCB*)arg; FAR _TCB *rtcb = (FAR _TCB*)arg;
@ -360,8 +360,10 @@ static int sem_boostholderprio(struct semholder_s *pholder, FAR sem_t *sem, FAR
****************************************************************************/ ****************************************************************************/
#ifdef CONFIG_DEBUG #ifdef CONFIG_DEBUG
static int sem_verifyholder(struct semholder_s *pholder, FAR sem_t *sem, FAR void *arg) static int sem_verifyholder(FAR struct semholder_s *pholder, FAR sem_t *sem, FAR void *arg)
{ {
// REMOVE ME
#if 0 // Need to revisit this, but these assumptions seem to be untrue -- OR there is a bug???
FAR _TCB *htcb = (FAR _TCB *)pholder->holder; FAR _TCB *htcb = (FAR _TCB *)pholder->holder;
/* Called after a semaphore has been released (incremented), the semaphore /* Called after a semaphore has been released (incremented), the semaphore
@ -373,6 +375,7 @@ static int sem_verifyholder(struct semholder_s *pholder, FAR sem_t *sem, FAR voi
DEBUGASSERT(htcb->npend_reprio == 0); DEBUGASSERT(htcb->npend_reprio == 0);
#endif #endif
DEBUGASSERT(htcb->sched_priority == htcb->base_priority); DEBUGASSERT(htcb->sched_priority == htcb->base_priority);
#endif
return 0; return 0;
} }
#endif #endif
@ -382,7 +385,7 @@ static int sem_verifyholder(struct semholder_s *pholder, FAR sem_t *sem, FAR voi
****************************************************************************/ ****************************************************************************/
#if defined(CONFIG_DEBUG) && defined(CONFIG_SEM_PHDEBUG) #if defined(CONFIG_DEBUG) && defined(CONFIG_SEM_PHDEBUG)
static int sem_dumpholder(struct semholder_s *pholder, FAR sem_t *sem, FAR void *arg) static int sem_dumpholder(FAR struct semholder_s *pholder, FAR sem_t *sem, FAR void *arg)
{ {
#if CONFIG_SEM_PREALLOCHOLDERS > 0 #if CONFIG_SEM_PREALLOCHOLDERS > 0
dbg(" %08x: %08x %08x %04x\n", dbg(" %08x: %08x %08x %04x\n",
@ -398,7 +401,7 @@ static int sem_dumpholder(struct semholder_s *pholder, FAR sem_t *sem, FAR void
* Name: sem_restoreholderprio * Name: sem_restoreholderprio
****************************************************************************/ ****************************************************************************/
static int sem_restoreholderprio(struct semholder_s *pholder, FAR sem_t *sem, FAR void *arg) static int sem_restoreholderprio(FAR struct semholder_s *pholder, FAR sem_t *sem, FAR void *arg)
{ {
FAR _TCB *htcb = (FAR _TCB *)pholder->holder; FAR _TCB *htcb = (FAR _TCB *)pholder->holder;
#if CONFIG_SEM_NNESTPRIO > 0 #if CONFIG_SEM_NNESTPRIO > 0
@ -431,11 +434,13 @@ static int sem_restoreholderprio(struct semholder_s *pholder, FAR sem_t *sem, FA
if (htcb->npend_reprio < 1) if (htcb->npend_reprio < 1)
{ {
/* No... the thread has only been boosted once */ /* No... the 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); DEBUGASSERT(htcb->sched_priority == stcb->sched_priority && htcb->npend_reprio == 0);
rpriority = htcb->base_priority; sched_reprioritize(htcb, htcb->base_priority);
} }
/* There are multiple pending priority levels. The thread's "boosted" /* There are multiple pending priority levels. The thread's "boosted"
* priority could greater than or equal to "stcb->sched_priority" (it could be * priority could greater than or equal to "stcb->sched_priority" (it could be
@ -469,9 +474,9 @@ static int sem_restoreholderprio(struct semholder_s *pholder, FAR sem_t *sem, FA
} }
htcb->npend_reprio = i; htcb->npend_reprio = i;
/* And apply that priority to the thread */ /* And apply that priority to the thread (while retaining the base_priority) */
sched_reprioritize(htcb, rpriority); sched_setpriority(htcb, rpriority);
} }
else else
{ {
@ -513,6 +518,31 @@ static int sem_restoreholderprio(struct semholder_s *pholder, FAR sem_t *sem, FA
return 0; return 0;
} }
/****************************************************************************
* Name: sem_restoreholderprioA & B
****************************************************************************/
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->holder != rtcb)
{
return sem_restoreholderprio(pholder, sem, arg);
}
return 0;
}
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->holder == rtcb)
{
(void)sem_restoreholderprio(pholder, sem, arg);
return 1;
}
return 0;
}
/**************************************************************************** /****************************************************************************
* Public Functions * Public Functions
****************************************************************************/ ****************************************************************************/
@ -568,8 +598,6 @@ void sem_initholders(void)
void sem_destroyholder(FAR sem_t *sem) void sem_destroyholder(FAR sem_t *sem)
{ {
FAR _TCB *rtcb = (FAR _TCB*)g_readytorun.head;
/* It is an error is a semaphore is destroyed while there are any holders /* It is an error is a semaphore is destroyed while there are any holders
* (except perhaps the thread releas the semaphore itself). Hmmm.. but * (except perhaps the thread releas the semaphore itself). Hmmm.. but
* we actually have to assume that the caller knows what it is doing because * we actually have to assume that the caller knows what it is doing because
@ -719,13 +747,14 @@ void sem_releaseholder(FAR sem_t *sem)
* 0 (OK) or -1 (ERROR) if unsuccessful * 0 (OK) or -1 (ERROR) if unsuccessful
* *
* Assumptions: * Assumptions:
* The scheduler is locked.
* *
****************************************************************************/ ****************************************************************************/
void sem_restorebaseprio(FAR _TCB *stcb, FAR sem_t *sem) void sem_restorebaseprio(FAR _TCB *stcb, FAR sem_t *sem)
{ {
FAR _TCB *rtcb = (FAR _TCB*)g_readytorun.head; FAR _TCB *rtcb = (FAR _TCB*)g_readytorun.head;
struct semholder_s *pholder; FAR struct semholder_s *pholder;
/* Check our assumptions */ /* Check our assumptions */
@ -736,9 +765,20 @@ void sem_restorebaseprio(FAR _TCB *stcb, FAR sem_t *sem)
if (stcb) if (stcb)
{ {
/* Adjust the priority of every holder as necessary */ /* The currently executed thread should be the low 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_restoreholderprio, stcb); (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 /* If there are no tasks waiting for available counts, then all holders
@ -753,8 +793,8 @@ void sem_restorebaseprio(FAR _TCB *stcb, FAR sem_t *sem)
#endif #endif
/* In any case, the currently execuing task should have an entry in the /* In any case, the currently execuing task should have an entry in the
* list and we need to decrement the number of counts that it holds. When it * list. Its counts were previously decremented; if it now holds no
* holds no further counts, it must be removed from the list of holders. * counts, then we need to remove it from the list of holders.
*/ */
pholder = sem_findholder(sem, rtcb); pholder = sem_findholder(sem, rtcb);