From 264806e5b23feacdd981b44da19eaa4d452b4ec1 Mon Sep 17 00:00:00 2001 From: patacongo Date: Fri, 13 Mar 2009 00:25:05 +0000 Subject: [PATCH] Add test for CONFIG_SEM_PREALLOCHOLDERS > 0 git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@1596 42af7a65-404d-4744-a932-0658087f49c3 --- Documentation/NuttxPortingGuide.html | 11 +- configs/README.txt | 8 + configs/sim/ostest/defconfig | 10 +- examples/ostest/prioinherit.c | 292 ++++++++++++++++++--------- include/semaphore.h | 2 +- sched/sem_holder.c | 3 + sched/sem_init.c | 2 + tools/mkconfig.c | 6 +- 8 files changed, 233 insertions(+), 101 deletions(-) diff --git a/Documentation/NuttxPortingGuide.html b/Documentation/NuttxPortingGuide.html index 4c3f3ff79d..a381c6a673 100644 --- a/Documentation/NuttxPortingGuide.html +++ b/Documentation/NuttxPortingGuide.html @@ -1627,9 +1627,18 @@ The system can be re-made subsequently by just typing make. errorcheck mutexes. Enables pthread_mutexattr_settype().
  • - CONFIG_PRIORITY_INHERITANCE : Set to enable support for + CONFIG_PRIORITY_INHERITANCE: Set to enable support for priority inheritance on mutexes and semaphores.
  • +
  • + CONFIG_SEM_PREALLOCHOLDERS: : This setting is only used + if priority inheritance is enabled. + It defines the maximum number of different threads (minus one) that + can take counts on a semaphore with priority inheritance support. + This may be set to zero if priority inheritance is disabled OR if you + are only using semaphores as mutexes (only one holder) OR if no more + than two threads participate using a counting semaphore. +
  • diff --git a/configs/README.txt b/configs/README.txt index cfd20b3b96..e6b656dc8c 100644 --- a/configs/README.txt +++ b/configs/README.txt @@ -199,6 +199,14 @@ defconfig -- This is a configuration file similar to the Linux errorcheck mutexes. Enables pthread_mutexattr_settype(). CONFIG_PRIORITY_INHERITANCE - Set to enable support for priority inheritance on mutexes and semaphores. + CONFIG_SEM_PREALLOCHOLDERS: This setting is only used if priority + inheritance is enabled. It defines the maximum number of + different threads (minus one) that can take counts on a + semaphore with priority inheritance support. This may be + set to zero if priority inheritance is disabled OR if you + are only using semaphores as mutexes (only one holder) OR + if no more than two threads participate using a counting + semaphore. The following can be used to disable categories of APIs supported by the OS. If the compiler supports weak functions, then it diff --git a/configs/sim/ostest/defconfig b/configs/sim/ostest/defconfig index e9beee06bb..32823d716d 100644 --- a/configs/sim/ostest/defconfig +++ b/configs/sim/ostest/defconfig @@ -85,7 +85,14 @@ CONFIG_ARCH_BOARD_SIM=y # CONFIG_MUTEX_TYPES: Set to enable support for recursive and # errorcheck mutexes. Enables pthread_mutexattr_settype(). # CONFIG_PRIORITY_INHERITANCE : Set to enable support for priority -# inheritance on mutexes and semaphores. +# inheritance on mutexes and semaphores. +# CONFIG_SEM_PREALLOCHOLDERS: This setting is only used if priority +# inheritance is enabled. It defines the maximum number of different +# threads (minus one) that can take counts on a semaphore with priority +# inheritance support. This may be set to zero if priority inheritance +# is disabled OR if you are only using semaphores as mutexes (only +# one holder) OR if no more than two threads participate using a +# counting semaphore. # CONFIG_EXAMPLE=ostest CONFIG_DEBUG=y @@ -103,6 +110,7 @@ CONFIG_DEV_CONSOLE=y CONFIG_DEV_LOWCONSOLE=n CONFIG_MUTEX_TYPES=y CONFIG_PRIORITY_INHERITANCE=n +CONFIG_SEM_PREALLOCHOLDERS=3 # # The following can be used to disable categories of diff --git a/examples/ostest/prioinherit.c b/examples/ostest/prioinherit.c index 7754ca5879..850c2fc303 100644 --- a/examples/ostest/prioinherit.c +++ b/examples/ostest/prioinherit.c @@ -42,6 +42,7 @@ #include #include #include +#include #ifdef CONFIG_ARCH_SIM # include @@ -55,6 +56,12 @@ * Definitions ****************************************************************************/ +#ifndef CONFIG_SEM_PREALLOCHOLDERS +# define CONFIG_SEM_PREALLOCHOLDERS 0 +#endif +#define NLOWPRI_THREADS (CONFIG_SEM_PREALLOCHOLDERS+1) +#define NHIGHPRI_THREADS 1 + /**************************************************************************** * Private Data ****************************************************************************/ @@ -72,43 +79,82 @@ enum thstate_e }; static sem_t g_sem; -static volatile enum thstate_e g_middlestate = NOTSTARTED; -static volatile enum thstate_e g_highstate = NOTSTARTED; -static volatile enum thstate_e g_lowstate = NOTSTARTED; +static volatile enum thstate_e g_middlestate; +static volatile enum thstate_e g_highstate[NHIGHPRI_THREADS]; +static volatile enum thstate_e g_lowstate[NLOWPRI_THREADS]; static int g_highpri; static int g_medpri; static int g_lowpri; +/**************************************************************************** + * Name: nhighpri_started + ****************************************************************************/ + +static int nhighpri_started(void) +{ + int n = 0; + int i; + + for (i = 0; i < NHIGHPRI_THREADS; i++) + { + if (g_highstate[i] != NOTSTARTED) + { + n++; + } + } + return n; +} + +/**************************************************************************** + * Name: nhighpri_running + ****************************************************************************/ + +static int nhighpri_running(void) +{ + int n = 0; + int i; + + for (i = 0; i < NHIGHPRI_THREADS; i++) + { + if (g_highstate[i] != DONE) + { + n++; + } + } + return n; +} + /**************************************************************************** * Name: highpri_thread ****************************************************************************/ static void *highpri_thread(void *parameter) { + int threadno = (int)parameter; int ret; - printf("highpri_thread: Started\n"); + printf("highpri_thread-%d: Started\n", threadno); fflush(stdout); - g_highstate = WAITING; - ret = sem_wait(&g_sem); - g_highstate = DONE; + g_highstate[threadno-1] = WAITING; + ret = sem_wait(&g_sem); + g_highstate[threadno-1] = DONE; if (ret != 0) { - printf("highpri_thread: sem_take failed: %d\n", ret); + printf("highpri_thread-%d: sem_take failed: %d\n", threadno, ret); } else if (g_middlestate == RUNNING) { - printf("highpri_thread: SUCCESS midpri_thread is still running!\n"); + printf("highpri_thread-%d: SUCCESS midpri_thread is still running!\n", threadno); } else { - printf("highpri_thread: ERROR -- midpri_thread has already exited!\n"); + printf("highpri_thread-%d: ERROR -- midpri_thread has already exited!\n", threadno); } sem_post(&g_sem); - printf("medpri_thread: Okay... I'm done!\n"); + printf("highpri_thread-%d: Okay... I'm done!\n", threadno); fflush(stdout); return NULL; } @@ -156,7 +202,7 @@ static void *medpri_thread(void *parameter) * will be boosted. */ - while (g_highstate != DONE) + while (nhighpri_running() > 0) { hog_cpu(); } @@ -175,87 +221,125 @@ static void *lowpri_thread(void *parameter) { void *retval = (void*)-1; struct sched_param sparam; + int threadno = (int)parameter; + int expected; + int count; int policy; int ret; + int nrunning; + int i; - g_lowstate = RUNNING; - printf("lowpri_thread: Started\n"); + g_lowstate[threadno-1] = RUNNING; + printf("lowpri_thread-%d: Started\n", threadno); ret = pthread_getschedparam(pthread_self(), &policy, &sparam); if (ret != 0) { - printf("lowpri_thread: ERROR pthread_getschedparam failed: %d\n", ret); + printf("lowpri_thread-%d: ERROR pthread_getschedparam failed: %d\n", threadno, ret); } else { - printf("lowpri_thread: initial priority: %d\n", sparam.sched_priority); + printf("lowpri_thread-%d: initial priority: %d\n", threadno, sparam.sched_priority); if (sparam.sched_priority != g_lowpri) { printf(" ERROR should have been %d\n", g_lowpri); } } - g_lowstate = WAITING; + g_lowstate[threadno-1] = WAITING; ret = sem_wait(&g_sem); if (ret != 0) { - printf("lowpri_thread: sem_take failed: %d\n", ret); + printf("lowpri_thread-%d: sem_take failed: %d\n", threadno, ret); } else { /* Hang on to the thread until the middle priority thread runs */ - while (g_middlestate == NOTSTARTED && g_highstate != WAITING) + while (g_middlestate == NOTSTARTED && nhighpri_started() < NHIGHPRI_THREADS) { - printf("lowpri_thread: Waiting for the midle pri task to run\n"); - printf(" g_middlestate=%d g_highstate=%d\n", (int)g_middlestate, (int)g_highstate); - printf(" I still have the semaphore\n"); + printf("lowpri_thread-%d: Waiting for the midle pri task to run\n", threadno); + printf(" g_middlestate: %d\n", (int)g_middlestate); + for (i = 0; i < NHIGHPRI_THREADS; i++) + { + printf(" g_highstate[%d]: %d\n", i, (int)g_highstate[i]); + } + printf(" I still have a count on the semaphore\n"); fflush(stdout); sleep(1); } + /* Account for all of the semaphore counts. At any given time if there are 'n' + * running hight prioity tasks, then the semaphore count should be '-n' + */ + + sched_lock(); /* Needs to be atomic */ + ret = sem_getvalue(&g_sem, &count); + nrunning = nhighpri_running(); + sched_unlock(); + + if (ret < 0) + { + 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); + /* The middle priority task is running, let go of the semaphore */ - if (g_middlestate == RUNNING && g_highstate == WAITING) - { - /* Good.. the middle priority task is still running but we got priority! */ + if (g_middlestate == RUNNING && nrunning == -count) + { + /* Good.. the middle priority task is still running and the counts are okay. */ - retval = NULL; - } - else - { - printf("lowpri_thread: ERROR the middle priority task has already exitted!\n"); - printf(" g_middlestate=%d g_highstate=%d\n", (int)g_middlestate, (int)g_highstate); - } + retval = NULL; + } + else + { + printf("lowpri_thread-%d: ERROR the middle priority task has already exitted!\n", threadno); + printf(" g_middlestate: %d sem count=%d\n", (int)g_middlestate, count); + for (i = 0; i < NHIGHPRI_THREADS; i++) + { + printf(" g_highstate[%d]: %d\n", i, (int)g_highstate[i]); + } + } } ret = pthread_getschedparam(pthread_self(), &policy, &sparam); sem_post(&g_sem); if (ret != 0) { - printf("lowpri_thread: ERROR pthread_getschedparam failed: %d\n", ret); + printf("lowpri_thread-%d: ERROR pthread_getschedparam failed: %d\n", threadno, ret); } else { - printf("lowpri_thread: %s priority before sem_post: %d\n", - sparam.sched_priority != g_highpri ? "ERROR" : "SUCCESS", + if (nhighpri_running() > 0) + { + expected = g_highpri; + } + else + { + expected = g_lowpri; + } + + printf("lowpri_thread-%d: %s priority before sem_post: %d\n", + threadno, + sparam.sched_priority != expected ? "ERROR" : "SUCCESS", sparam.sched_priority); - if (sparam.sched_priority != g_highpri) + if (sparam.sched_priority != expected) { - printf(" ERROR should have been %d\n", g_highpri); - } + printf(" ERROR should have been %d\n", expected); + } } - ret = pthread_getschedparam(pthread_self(), &policy, &sparam); if (ret != 0) { - printf("lowpri_thread: ERROR pthread_getschedparam failed: %d\n", ret); + printf("lowpri_thread-%d: ERROR pthread_getschedparam failed: %d\n", threadno, ret); } else { - printf("lowpri_thread: %s final priority: %d\n", + printf("lowpri_thread-%d: %s final priority: %d\n", + threadno, sparam.sched_priority != g_lowpri ? "ERROR" : "SUCCESS", sparam.sched_priority); @@ -265,9 +349,9 @@ static void *lowpri_thread(void *parameter) } } - printf("lowpri_thread: Okay... I'm done!\n"); + printf("lowpri_thread-%d: Okay... I'm done!\n", threadno); fflush(stdout); - g_lowstate = DONE; + g_lowstate[threadno-1] = DONE; return retval; } #endif /* CONFIG_PRIORITY_INHERITANCE && !CONFIG_DISABLE_SIGNALS && !CONFIG_DISABLE_PTHREAD */ @@ -283,14 +367,15 @@ static void *lowpri_thread(void *parameter) void priority_inheritance(void) { #if defined(CONFIG_PRIORITY_INHERITANCE) && !defined(CONFIG_DISABLE_SIGNALS) && !defined(CONFIG_DISABLE_PTHREAD) - pthread_t lowpri; + pthread_t lowpri[NLOWPRI_THREADS]; pthread_t medpri; - pthread_t highpri; + pthread_t highpri[NHIGHPRI_THREADS]; pthread_addr_t result; pthread_attr_t attr; struct sched_param sparam; int my_pri; int status; + int i; printf("priority_inheritance: Started\n"); @@ -306,37 +391,42 @@ void priority_inheritance(void) g_lowpri = sched_get_priority_min(SCHED_FIFO); g_medpri = my_pri - 1; - sem_init(&g_sem, 0, 1); + sem_init(&g_sem, 0, NLOWPRI_THREADS); - /* Start the low priority task */ + /* Start the low priority threads */ - printf("priority_inheritance: Starting lowpri_thread at %d\n", g_lowpri); - status = pthread_attr_init(&attr); - if (status != 0) + for (i = 0; i < NLOWPRI_THREADS; i++) { - printf("priority_inheritance: pthread_attr_init failed, status=%d\n", status); - } - sparam.sched_priority = g_lowpri; - status = pthread_attr_setschedparam(&attr,& sparam); - if (status != OK) - { - printf("priority_inheritance: pthread_attr_setschedparam failed, status=%d\n", status); - } - else - { - printf("priority_inheritance: Set lowpri_thread priority to %d\n", sparam.sched_priority); - } + int threadno = i+1; + printf("priority_inheritance: Starting lowpri_thread-%d (of %d) at %d\n", + threadno, NLOWPRI_THREADS, g_lowpri); + status = pthread_attr_init(&attr); + if (status != 0) + { + printf("priority_inheritance: pthread_attr_init failed, status=%d\n", status); + } + sparam.sched_priority = g_lowpri; + status = pthread_attr_setschedparam(&attr,& sparam); + if (status != OK) + { + printf("priority_inheritance: pthread_attr_setschedparam failed, status=%d\n", status); + } + else + { + printf("priority_inheritance: Set lowpri_thread-%d priority to %d\n", + threadno, sparam.sched_priority); + } - status = pthread_create(&lowpri, &attr, lowpri_thread, NULL); - if (status != 0) - { - printf("priority_inheritance: pthread_create failed, status=%d\n", status); + status = pthread_create(&lowpri[i], &attr, lowpri_thread, (void*)threadno); + if (status != 0) + { + printf("priority_inheritance: pthread_create failed, status=%d\n", status); + } } - printf("priority_inheritance: Waiting...\n"); sleep(2); - /* Start the medium priority task */ + /* Start the medium priority thread */ printf("priority_inheritance: Starting medpri_thread at %d\n", g_medpri); status = pthread_attr_init(&attr); @@ -365,44 +455,56 @@ void priority_inheritance(void) printf("priority_inheritance: Waiting...\n"); sleep(1); - /* Start the high priority task */ + /* Start the high priority threads */ - printf("priority_inheritance: Starting highpri_thread at %d\n", g_highpri); - status = pthread_attr_init(&attr); - if (status != 0) + for (i = 0; i < NHIGHPRI_THREADS; i++) { - printf("priority_inheritance: pthread_attr_init failed, status=%d\n", status); - } + int threadno = i+1; + printf("priority_inheritance: Starting highpri_thread-%d (of %d) at %d\n", + threadno, NHIGHPRI_THREADS, g_highpri); + status = pthread_attr_init(&attr); + if (status != 0) + { + printf("priority_inheritance: pthread_attr_init failed, status=%d\n", status); + } - sparam.sched_priority = g_highpri; - status = pthread_attr_setschedparam(&attr,& sparam); - if (status != OK) - { - printf("priority_inheritance: pthread_attr_setschedparam failed, status=%d\n", status); - } - else - { - printf("priority_inheritance: Set highpri_thread priority to %d\n", sparam.sched_priority); - } - fflush(stdout); + sparam.sched_priority = g_highpri; + status = pthread_attr_setschedparam(&attr,& sparam); + if (status != OK) + { + printf("priority_inheritance: pthread_attr_setschedparam failed, status=%d\n", status); + } + else + { + printf("priority_inheritance: Set highpri_thread-%d priority to %d\n", + threadno, sparam.sched_priority); + } + fflush(stdout); - status = pthread_create(&medpri, &attr, highpri_thread, NULL); - if (status != 0) - { - printf("priority_inheritance: pthread_create failed, status=%d\n", status); + status = pthread_create(&highpri[i], &attr, highpri_thread, (void*)threadno); + if (status != 0) + { + printf("priority_inheritance: pthread_create failed, status=%d\n", status); + } } /* Wait for all thread instances to complete */ - printf("priority_inheritance: Waiting for highpri_thread to complete\n"); - fflush(stdout); - (void)pthread_join(highpri, &result); + for (i = 0; i < NLOWPRI_THREADS; i++) + { + printf("priority_inheritance: Waiting for highpri_thread-%d to complete\n", i+1); + fflush(stdout); + (void)pthread_join(highpri[i], &result); + } printf("priority_inheritance: Waiting for medpri_thread to complete\n"); fflush(stdout); (void)pthread_join(medpri, &result); - printf("priority_inheritance: Waiting for lowpri_thread to complete\n"); - fflush(stdout); - (void)pthread_join(lowpri, &result); + for (i = 0; i < NLOWPRI_THREADS; i++) + { + printf("priority_inheritance: Waiting for lowpri_thread-%d to complete\n", i+1); + fflush(stdout); + (void)pthread_join(lowpri[i], &result); + } printf("priority_inheritance: Finished\n"); sem_destroy(&g_sem); diff --git a/include/semaphore.h b/include/semaphore.h index 8061d3d5d3..9f38667c18 100644 --- a/include/semaphore.h +++ b/include/semaphore.h @@ -63,7 +63,7 @@ extern "C" { #ifdef CONFIG_PRIORITY_INHERITANCE struct semholder_s { -#if !defined(CONFIG_SEM_PREALLOCHOLDERS) || CONFIG_SEM_PREALLOCHOLDERS > 0 +#if CONFIG_SEM_PREALLOCHOLDERS > 0 struct semholder_s *flink; /* Implements singly linked list */ #endif void *holder; /* Holder TCB (actual type is _TCB) */ diff --git a/sched/sem_holder.c b/sched/sem_holder.c index 0477a67e2a..3806bfdc9f 100644 --- a/sched/sem_holder.c +++ b/sched/sem_holder.c @@ -218,6 +218,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) { struct semholder_s *pholder = &sem->hlist; +#if CONFIG_SEM_PREALLOCHOLDERS > 0 + struct semholder_s *next; +#endif int ret = 0; #if CONFIG_SEM_PREALLOCHOLDERS > 0 diff --git a/sched/sem_init.c b/sched/sem_init.c index 05485a600a..65707949fe 100644 --- a/sched/sem_init.c +++ b/sched/sem_init.c @@ -99,7 +99,9 @@ int sem_init (FAR sem_t *sem, int pshared, unsigned int value) { sem->semcount = (sint16)value; #ifdef CONFIG_PRIORITY_INHERITANCE +#if CONFIG_SEM_PREALLOCHOLDERS > 0 sem->hlist.flink = NULL; +#endif sem->hlist.holder = NULL; sem->hlist.counts = 0; #endif diff --git a/tools/mkconfig.c b/tools/mkconfig.c index 82cff503bf..6b2299e7be 100644 --- a/tools/mkconfig.c +++ b/tools/mkconfig.c @@ -243,11 +243,11 @@ int main(int argc, char **argv, char **envp) printf("/* If priority inheritance is disabled, then do not allocate any\n"); printf(" * associated resources.\n"); printf(" */\n\n"); - printf("#if !defined(CONFIG_PROIRITY_INHERITANCE) || !defined(CONFIG_SEM_PREALLOCHOLDERSS)\n"); + printf("#if !defined(CONFIG_PRIORITY_INHERITANCE) || !defined(CONFIG_SEM_PREALLOCHOLDERS)\n"); printf("# undef CONFIG_SEM_PREALLOCHOLDERS\n"); - printf("# define CONFIG_SEM_PREALLOCHOLDERSS 0\n"); + printf("# define CONFIG_SEM_PREALLOCHOLDERS 0\n"); printf("#endif\n\n"); - printf("#if !defined(CONFIG_PROIRITY_INHERITANCE) || !defined(CONFIG_SEM_NNESTPRIO)\n"); + printf("#if !defined(CONFIG_PRIORITY_INHERITANCE) || !defined(CONFIG_SEM_NNESTPRIO)\n"); printf("# undef CONFIG_SEM_NNESTPRIO\n"); printf("# define CONFIG_SEM_NNESTPRIO 0\n"); printf("#endif\n\n");