diff --git a/ChangeLog.txt b/ChangeLog.txt index d6e2e2973..5c59eec58 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1363,3 +1363,6 @@ On very fast processors, there are race conditions that make the test failure. Need better interlocking to assure that the threads actually do start at the same time (2015-07-24). + * apps/examples/ostest: Add a test for the sporadic scheduler. This + test is failing as of this commit (2015-07-24). + diff --git a/examples/ostest/Makefile b/examples/ostest/Makefile index 5831ad914..d591ce3f2 100644 --- a/examples/ostest/Makefile +++ b/examples/ostest/Makefile @@ -63,15 +63,22 @@ endif ifneq ($(CONFIG_DISABLE_PTHREAD),y) CSRCS += cancel.c cond.c mutex.c sem.c semtimed.c barrier.c + ifeq ($(CONFIG_FS_NAMED_SEMAPHORES),y) CSRCS += nsem.c endif -ifneq ($(CONFIG_RR_INTERVAL),0) -CSRCS += roundrobin.c -endif # CONFIG_RR_INTERVAL + ifeq ($(CONFIG_MUTEX_TYPES),y) CSRCS += rmutex.c -endif # CONFIG_MUTEX_TYPES +endif + +ifneq ($(CONFIG_RR_INTERVAL),0) +CSRCS += roundrobin.c +endif + +ifeq ($(CONFIG_SCHED_SPORADIC),y) +CSRCS += sporadic.c +endif endif # CONFIG_DISABLE_PTHREAD ifneq ($(CONFIG_DISABLE_SIGNALS),y) diff --git a/examples/ostest/ostest.h b/examples/ostest/ostest.h index 5f6b8a5bf..6512c7547 100644 --- a/examples/ostest/ostest.h +++ b/examples/ostest/ostest.h @@ -187,6 +187,10 @@ void timer_test(void); void rr_test(void); +/* sporadic.c *************************************************************/ + +void sporadic_test(void); + /* barrier.c ****************************************************************/ void barrier_test(void); diff --git a/examples/ostest/ostest_main.c b/examples/ostest/ostest_main.c index 95f94b7c8..b972a6544 100644 --- a/examples/ostest/ostest_main.c +++ b/examples/ostest/ostest_main.c @@ -474,6 +474,14 @@ static int user_main(int argc, char *argv[]) check_test_memory_usage(); #endif +#if !defined(CONFIG_DISABLE_PTHREAD) && defined(CONFIG_SCHED_SPORADIC) + /* Verify sporadic scheduling */ + + printf("\nuser_main: sporadic scheduler test\n"); + sporadic_test(); + check_test_memory_usage(); +#endif + #ifndef CONFIG_DISABLE_PTHREAD /* Verify pthread barriers */ diff --git a/examples/ostest/roundrobin.c b/examples/ostest/roundrobin.c index f0911679d..5a807cf5f 100644 --- a/examples/ostest/roundrobin.c +++ b/examples/ostest/roundrobin.c @@ -195,7 +195,7 @@ void rr_test(void) printf("rr_test: Set thread policy to SCHED_RR\n"); } - /* This semaphore will prevent anything from running */ + /* This semaphore will prevent anything from running until we are ready */ sched_lock(); sem_init(&g_rrsem, 0, 0); @@ -231,6 +231,7 @@ void rr_test(void) pthread_join(get_primes2_thread, &result); pthread_join(get_primes1_thread, &result); printf("rr_test: Done\n"); + sem_destroy(&g_rrsem); } #endif /* CONFIG_RR_INTERVAL */ diff --git a/examples/ostest/sporadic.c b/examples/ostest/sporadic.c new file mode 100644 index 000000000..b2f2e8568 --- /dev/null +++ b/examples/ostest/sporadic.c @@ -0,0 +1,261 @@ +/*********************************************************************** + * apps/examples/ostest/sporadic.c + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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 + +#include +#include +#include +#include +#include + +#include "ostest.h" + +#ifdef CONFIG_SCHED_SPORADIC + +/*********************************************************************** + * Pre-processor Definitions + ***********************************************************************/ + +#ifndef NULL +# define NULL (void*)0 +#endif + +/*********************************************************************** + * Private Data + ***********************************************************************/ + +static sem_t g_sporadic_sem; + +/*********************************************************************** + * Private Functions + ***********************************************************************/ + +static void *fifo_func(void *parameter) +{ + struct sched_param param; + int ret; + int i; + + while (sem_wait(&g_sporadic_sem) < 0); + + for (;;) + { + for (i = 0; i < 1000; i++) + { + ret = sched_getparam(0, ¶m); + if (ret < 0) + { + printf("ERROR: sched_getparam failed\n"); + return NULL; + } + } + + printf("FIFO: %d\n", param.sched_priority); + } +} + +static void *sporadic_func(void *parameter) +{ + struct sched_param param; + int prio = 0; + int ret; + int i; + + while (sem_wait(&g_sporadic_sem) < 0); + + for (;;) + { + for (i = 0; i < 1000; i++) + { + ret = sched_getparam(0, ¶m); + if (ret < 0) + { + printf("ERROR: sched_getparam failed\n"); + return NULL; + } + + if (prio != param.sched_priority) + { + break; + } + } + + prio = param.sched_priority; + printf("SPORADIC: %d\n", prio); + } +} + +/*********************************************************************** + * Public Functions + ***********************************************************************/ + +void sporadic_test(void) +{ + pthread_t sporadic_thread = (pthread_t)0; + pthread_t fifo_thread = (pthread_t)0; +#ifdef SDCC + pthread_addr_t result; +#endif + FAR void *result; + struct sched_param myparam; + struct sched_param sparam; + int prio_min; + int prio_max; + int prio_low; + int prio_mid; + int prio_high; + pthread_attr_t attr; + int ret; + + printf("sporadic_test: Initializing semaphore to 0\n"); + sem_init(&g_sporadic_sem, 0, 0); + + prio_min = sched_get_priority_min(SCHED_FIFO); + prio_max = sched_get_priority_max(SCHED_FIFO); + + prio_low = prio_min + ((prio_max - prio_min) >> 2); + prio_mid = (prio_min + prio_max) >> 1; + prio_high = prio_max - ((prio_max - prio_min) >> 2); + + /* Temporarily set our priority to prio_high + 1 */ + + ret = sched_getparam(0, &myparam); + if (ret != OK) + { + printf("sporadic_test: ERROR: sched_getparam failed, ret=%d\n", ret); + } + + sparam.sched_priority = prio_high+1; + ret = sched_setparam(0, &sparam); + if (ret != OK) + { + printf("sporadic_test: ERROR: sched_setparam failed, ret=%d\n", ret); + } + + ret = pthread_attr_init(&attr); + if (ret != OK) + { + printf("sporadic_test: ERROR: pthread_attr_init failed, ret=%d\n", ret); + } + + /* This semaphore will prevent anything from running until we are ready */ + + sched_lock(); + sem_init(&g_sporadic_sem, 0, 0); + + /* Start a FIFO thread at the middle priority */ + + printf("sporadic_test: Starting FIFO thread at priority %d\n", prio_mid); + + ret = pthread_attr_setschedpolicy(&attr, SCHED_FIFO); + if (ret != OK) + { + printf("sporadic_test: ERROR: pthread_attr_setschedpolicy failed, ret=%d\n", ret); + } + + sparam.sched_priority = prio_mid; + ret = pthread_attr_setschedparam(&attr, &sparam); + if (ret != OK) + { + printf("sporadic_test: ERROR: pthread_attr_setschedparam failed, ret=%d\n", ret); + } + + ret = pthread_create(&fifo_thread, &attr, fifo_func, NULL); + if (ret != 0) + { + printf("sporadic_test: ERROR: FIFO thread creation failed: %d\n", ret); + } + + /* Start a sporadic thread, with the following parameters: */ + + printf("sporadic_test: Starting sporadic thread at priority %d/\n", prio_high, prio_low); + + ret = pthread_attr_setschedpolicy(&attr, SCHED_SPORADIC); + if (ret != OK) + { + printf("sporadic_test: ERROR: pthread_attr_setschedpolicy failed, ret=%d\n", ret); + } + + sparam.sched_priority = prio_high; + sparam.sched_ss_low_priority = prio_low; + sparam.sched_ss_repl_period.tv_sec = 4; + sparam.sched_ss_repl_period.tv_nsec = 0; + sparam.sched_ss_init_budget.tv_sec = 2; + sparam.sched_ss_max_repl = 5; + + ret = pthread_attr_setschedparam(&attr, &sparam); + if (ret != OK) + { + printf("sporadic_test: ERROR: pthread_attr_setsched param failed, ret=%d\n", ret); + } + + ret = pthread_create(&sporadic_thread, &attr, sporadic_func, (pthread_addr_t)1); + if (ret != 0) + { + printf("sporadic_test: ERROR: sporadic thread creation failed: %d\n", ret); + } + + sem_post(&g_sporadic_sem); + sem_post(&g_sporadic_sem); + + /* Wait a while then kill the FIFO thread */ + + sleep(12); + ret = pthread_cancel(fifo_thread); + pthread_join(fifo_thread, &result); + + /* Wait a bit longer */ + + sleep(12); + ret = pthread_cancel(sporadic_thread); + pthread_join(sporadic_thread, &result); + sched_unlock(); + + printf("sporadic_test: Done\n"); + sem_destroy(&g_sporadic_sem); + + ret = sched_setparam(0, &myparam); + if (ret != OK) + { + printf("sporadic_test: ERROR: sched_setparam failed, ret=%d\n", ret); + } +} + +#endif /* CONFIG_SCHED_SPORADIC */ \ No newline at end of file