/**************************************************************************** * apps/testing/ostest/sporadic.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include #include #include #include "ostest.h" #ifdef CONFIG_SCHED_SPORADIC /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ /* It is actually a better test without schedule locking because that * forces the scheduler into an uninteresting fallback mode. */ #undef sched_lock #undef sched_unlock #define sched_lock() #define sched_unlock() #ifndef MIN # define MIN(a,b) (((a) < (b)) ? (a) : (b)) #endif /**************************************************************************** * Private Data ****************************************************************************/ static sem_t g_sporadic_sem; static time_t g_start_time; /**************************************************************************** * Private Functions ****************************************************************************/ static void my_mdelay(unsigned int milliseconds) { volatile unsigned int i; volatile unsigned int j; for (i = 0; i < milliseconds; i++) { for (j = 0; j < CONFIG_BOARD_LOOPSPERMSEC; j++) { } } } static void *nuisance_func(void *parameter) { /* Synchronized start */ while (sem_wait(&g_sporadic_sem) < 0); /* Sleep until we are cancelled */ for (; ; ) { /* Sleep gracefully for awhile */ usleep(500 * 1000); /* Then hog some CPU time */ my_mdelay(100); } return NULL; } static void *fifo_func(void *parameter) { struct sched_param param; time_t last; time_t now; int ret; while (sem_wait(&g_sporadic_sem) < 0); last = g_start_time; for (; ; ) { do { sched_lock(); /* Just to exercise more logic */ ret = sched_getparam(0, ¶m); if (ret < 0) { printf("ERROR: sched_getparam failed\n"); return NULL; } now = time(NULL); sched_unlock(); } while (now == last); sched_lock(); /* Just to exercise more logic */ printf("%4lu FIFO: %d\n", (unsigned long)(now - g_start_time), param.sched_priority); last = now; sched_unlock(); } } static FAR void *sporadic_func(FAR void *parameter) { struct sched_param param; time_t last; time_t now; int prio = 0; int ret; while (sem_wait(&g_sporadic_sem) < 0); last = g_start_time; for (; ; ) { do { sched_lock(); /* Just to exercise more logic */ ret = sched_getparam(0, ¶m); if (ret < 0) { printf("ERROR: sched_getparam failed\n"); return NULL; } now = time(NULL); sched_unlock(); } while (now == last && prio == param.sched_priority); sched_lock(); /* Just to exercise more logic */ printf("%4lu SPORADIC: %d->%d\n", (unsigned long)(now - g_start_time), prio, param.sched_priority); prio = param.sched_priority; last = now; sched_unlock(); } } /**************************************************************************** * Public Functions ****************************************************************************/ void sporadic_test(void) { pthread_t nuisance_thread = (pthread_t)0; 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; #if CONFIG_SCHED_SPORADIC_MAXREPL < 5 printf("sporadic_test: CONFIG_SCHED_SPORADIC_MAXREPL is small: %d\n", CONFIG_SCHED_SPORADIC_MAXREPL); printf(" -- There will some errors in the replenishment interval\n"); #endif 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 + 2 */ ret = sched_getparam(0, &myparam); if (ret != OK) { printf("sporadic_test: ERROR: sched_getparam failed, ret=%d\n", ret); } sparam.sched_priority = prio_high + 2; 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 highest priority (prio_max + 1) */ 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_high + 1; ret = pthread_attr_setschedparam(&attr, &sparam); if (ret != OK) { printf("sporadic_test: ERROR: pthread_attr_setschedparam failed, " "ret=%d\n", ret); } ret = pthread_create(&nuisance_thread, &attr, nuisance_func, NULL); if (ret != 0) { printf("sporadic_test: ERROR: FIFO thread creation failed: %d\n", ret); } /* Start a FIFO thread at the middle priority */ 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 (hi) %d (lo)\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 = 5; sparam.sched_ss_repl_period.tv_nsec = 0; sparam.sched_ss_init_budget.tv_sec = 2; sparam.sched_ss_init_budget.tv_nsec = 0; sparam.sched_ss_max_repl = CONFIG_SCHED_SPORADIC_MAXREPL; 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); } g_start_time = time(NULL); sem_post(&g_sporadic_sem); sem_post(&g_sporadic_sem); sem_post(&g_sporadic_sem); /* Wait a while then kill the FIFO thread */ sleep(15); ret = pthread_cancel(fifo_thread); pthread_join(fifo_thread, &result); /* Wait a bit longer then kill the nuisance thread */ sleep(10); ret = pthread_cancel(nuisance_thread); pthread_join(nuisance_thread, &result); /* Wait a bit longer then kill the sporadic thread */ sleep(10); 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 */