From 27e21710fd1f8eda6a9bfc1deeb320a90cf58529 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sat, 25 Jul 2015 12:50:53 -0600 Subject: [PATCH] This is basically a complete redesign of the sporadic scheduling logic due to limitations in the initial design --- TODO | 20 +- include/nuttx/sched.h | 73 ++- sched/Kconfig | 12 +- sched/pthread/pthread_create.c | 133 ++--- sched/sched/sched.h | 8 +- sched/sched/sched_getparam.c | 31 +- sched/sched/sched_setparam.c | 72 ++- sched/sched/sched_setscheduler.c | 85 +++- sched/sched/sched_sporadic.c | 736 ++++++++++++++++++++++------ sched/sched/sched_timerexpiration.c | 2 +- 10 files changed, 887 insertions(+), 285 deletions(-) diff --git a/TODO b/TODO index c46328f076..17f0905874 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,4 @@ -NuttX TODO List (Last updated July 14, 2015) +NuttX TODO List (Last updated July 25, 2015) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This file summarizes known NuttX bugs, limitations, inconsistencies with @@ -9,7 +9,7 @@ issues reated to each board port. nuttx/ - (11) Task/Scheduler (sched/) + (12) Task/Scheduler (sched/) (1) Memory Management (mm/) (3) Signals (sched/signal, arch/) (2) pthreads (sched/pthread) @@ -213,6 +213,22 @@ o Task/Scheduler (sched/) Status: Open Priority: Medium-ish + Title: TICKLESS SCHEDULING INACCURACIES + Description: Interval timers are set up to determine timing for round- + robin and sporadic scheduling policies. In the timer + interrupt mode, the budget remaining for the thread is + decremented on each timer interrupt and so is always + accurate to within one clock time. So when the task + suspended, the remaining budget is accurate. + + But in tickless mode, the budget is only updated on the + expiration of the timer. So if the task is suspended by an + asynchronous event, the budget will fail to decrement and the + task will get a larger share of CPU that is deserves in those + cases. + Status: Open + Priority: Low. I am not aware of any real world issues. + o Memory Managment (mm/) ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/include/nuttx/sched.h b/include/nuttx/sched.h index 10821cb983..74a44d3fe0 100644 --- a/include/nuttx/sched.h +++ b/include/nuttx/sched.h @@ -116,6 +116,12 @@ # undef HAVE_GROUP_MEMBERS #endif +/* Sporadic scheduling */ + +#ifndef CONFIG_SCHED_SPORADIC_MAXREPL +# define CONFIG_SCHED_SPORADIC_MAXREPL 3 +#endif + /* Task Management Definitions **************************************************/ /* Special task IDS. Any negative PID is invalid. */ @@ -234,10 +240,49 @@ typedef CODE void (*atexitfunc_t)(void); typedef CODE void (*onexitfunc_t)(int exitcode, FAR void *arg); #endif +/* struct sporadic_s *************************************************************/ + +#ifdef CONFIG_SCHED_SPORADIC + +/* This structure represents oen replenishment interval. This is what is + * received by each timeout handler. + */ + +struct sporadic_s; +struct replenishment_s +{ + FAR struct tcb_s *tcb; /* The parent TCB structure */ + struct wdog_s timer; /* Timer dedicated to this interval */ + bool active; /* True: replenishment instance is busy */ +}; + +/* This structure is an allocated "plug-in" to the main TCB structure. It is + * allocated when the sporadic scheduling policy is assigned to a thread. Thus, + * in the context of numerous threads of varying policies, there the overhead + * from this significant allocation is only borne by the threads with the + * sporadic scheduling policy. + */ + +struct sporadic_s +{ + uint8_t hi_priority; /* Sporadic high priority */ + uint8_t low_priority; /* Sporadic low priority */ + uint8_t max_repl; /* Maximum number of replenishments */ + uint8_t nrepls; /* Number of active replenishments */ + uint32_t repl_period; /* Sporadic replenishment period */ + uint32_t budget; /* Sporadic execution budget period */ + uint32_t pending; /* Unrealized, pending execution time */ + + /* This is the list of replenishment intervals */ + + struct replenishment_s replenishments[CONFIG_SCHED_SPORADIC_MAXREPL]; +}; + +#endif /* CONFIG_SCHED_SPORADIC */ + /* struct child_status_s *********************************************************/ -/* This structure is used to maintin information about child tasks. - * pthreads work differently, they have join information. This is - * only for child tasks. +/* This structure is used to maintain information about child tasks. pthreads + * work differently, they have join information. This is only for child tasks. */ #ifdef CONFIG_SCHED_CHILD_STATUS @@ -245,9 +290,9 @@ struct child_status_s { FAR struct child_status_s *flink; - uint8_t ch_flags; /* Child status: See CHILD_FLAG_* definitions */ - pid_t ch_pid; /* Child task ID */ - int ch_status; /* Child exit status */ + uint8_t ch_flags; /* Child status: See CHILD_FLAG_* defns */ + pid_t ch_pid; /* Child task ID */ + int ch_status; /* Child exit status */ }; #endif @@ -478,20 +523,12 @@ struct tcb_s entry_t entry; /* Entry Point into the thread */ uint8_t sched_priority; /* Current priority of the thread */ -#if defined(CONFIG_PRIORITY_INHERITANCE) && CONFIG_PRIORITY_INHERITANCE > 0 +#ifdef CONFIG_PRIORITY_INHERITANCE +#if CONFIG_SEM_NNESTPRIO > 0 uint8_t npend_reprio; /* Number of nested reprioritizations */ uint8_t pend_reprios[CONFIG_SEM_NNESTPRIO]; #endif -#if defined(CONFIG_PRIORITY_INHERITANCE) || defined(CONFIG_SCHED_SPORADIC) uint8_t base_priority; /* "Normal" priority of the thread */ -#endif -#ifdef CONFIG_SCHED_SPORADIC - uint8_t hi_priority; /* Sporadic high priority */ - uint8_t low_priority; /* Sporadic low priority */ -#ifdef __REVISIT_REPLENISHMENTS - uint8_t max_repl; /* Max. replenishments */ - uint8_t nrepl; /* Number replenishments remaining */ -#endif #endif uint8_t task_state; /* Current state of the thread */ @@ -503,9 +540,7 @@ struct tcb_s /* interval remaining */ #endif #ifdef CONFIG_SCHED_SPORADIC - uint32_t repl_period; /* Sporadic replenishment period */ - uint32_t budget; /* Sporadic execution budget */ - struct wdog_s low_dog; /* Times low-priority interval */ + FAR struct sporadic_s *sporadic; /* Sporadic scheduling parameters */ #endif FAR struct wdog_s *waitdog; /* All timed waits use this timer */ diff --git a/sched/Kconfig b/sched/Kconfig index a94f2fa307..6128057996 100644 --- a/sched/Kconfig +++ b/sched/Kconfig @@ -311,7 +311,17 @@ config SCHED_SPORADIC bool "Support sporadic scheduling" default n ---help--- - Build in additional logic to support sporadic scheduling (SCHED_SPORADIC). + Build in additional logic to support sporadic scheduling + (SCHED_SPORADIC). + +config SCHED_SPORADIC_MAXREPL + int "Maximum number of replenishments" + default 3 + range 1 255 + depends on SCHED_SPORADIC + ---help--- + Controls the size of allocated replenishment structures and, hence, + also limits the maximum number of replenishments. config TASK_NAME_SIZE int "Maximum task name size" diff --git a/sched/pthread/pthread_create.c b/sched/pthread/pthread_create.c index df175c7982..b5df6364c7 100644 --- a/sched/pthread/pthread_create.c +++ b/sched/pthread/pthread_create.c @@ -228,7 +228,7 @@ int pthread_create(FAR pthread_t *thread, FAR const pthread_attr_t *attr, { FAR struct pthread_tcb_s *ptcb; FAR struct join_s *pjoin; - int priority; + struct sched_param param; int policy; int errcode; pid_t pid; @@ -298,18 +298,13 @@ int pthread_create(FAR pthread_t *thread, FAR const pthread_attr_t *attr, goto errout_with_join; } - /* Should we use the priority and scheduler specified in the - * pthread attributes? Or should we use the current thread's - * priority and scheduler? + /* Should we use the priority and scheduler specified in the pthread + * attributes? Or should we use the current thread's priority and + * scheduler? */ if (attr->inheritsched == PTHREAD_INHERIT_SCHED) { - struct sched_param param; -#ifdef CONFIG_SCHED_SPORADIC - int ticks; -#endif - /* Get the priority (and any other scheduling parameters) for this * thread. */ @@ -321,8 +316,6 @@ int pthread_create(FAR pthread_t *thread, FAR const pthread_attr_t *attr, goto errout_with_join; } - priority = param.sched_priority; - /* Get the scheduler policy for this thread */ policy = sched_getscheduler(0); @@ -331,71 +324,81 @@ int pthread_create(FAR pthread_t *thread, FAR const pthread_attr_t *attr, errcode = get_errno(); goto errout_with_join; } - -#ifdef CONFIG_SCHED_SPORADIC - /* Save the sporadic scheduling parameters */ - - ptcb->cmn.hi_priority = priority; - ptcb->cmn.low_priority = param.sched_ss_low_priority; -#ifdef __REVISIT_REPLENISHMENTS - ptcb->cmn.max_repl = param.sched_ss_max_repl; -#endif - - (void)clock_time2ticks(¶m.sched_ss_repl_period, &ticks); - ptcb->cmn.repl_period = ticks; - - (void)clock_time2ticks(¶m.sched_ss_init_budget, &ticks); - ptcb->cmn.budget = ticks; -#endif } else { - /* Use the priority and scheduler from the attributes */ + /* Use the scheduler policy and policy the attributes */ - priority = attr->priority; - policy = attr->policy; + policy = attr->policy; + param.sched_priority = attr->priority; #ifdef CONFIG_SCHED_SPORADIC - if (policy == SCHED_SPORADIC) - { - int repl_ticks; - int budget_ticks; - - /* Convert timespec values to system clock ticks */ - - (void)clock_time2ticks(&attr->repl_period, &repl_ticks); - (void)clock_time2ticks(&attr->budget, &budget_ticks); - - /* The replenishment period must be greater than or equal to the - * budget period. - */ - - if (repl_ticks < budget_ticks) - { - errcode = EINVAL; - goto errout_with_join; - } - - /* Save the sporadic scheduling parameters */ - - ptcb->cmn.hi_priority = priority; - ptcb->cmn.low_priority = attr->low_priority; -#ifdef __REVISIT_REPLENISHMENTS - ptcb->cmn.max_repl = attr->max_repl; -#endif - ptcb->cmn.repl_period = repl_ticks; - ptcb->cmn.budget = budget_ticks; - - /* And start the frist replenishment interval */ - - DEBUGVERIFY(sched_sporadic_start(&ptcb->cmn)); - } + param.sched_ss_low_priority = attr->low_priority; + param.sched_ss_max_repl = attr->max_repl; + param.sched_ss_repl_period.tv_sec = attr->repl_period.tv_sec; + param.sched_ss_repl_period.tv_nsec = attr->repl_period.tv_nsec; + param.sched_ss_init_budget.tv_sec = attr->budget.tv_sec; + param.sched_ss_init_budget.tv_nsec = attr->budget.tv_nsec; #endif } +#ifdef CONFIG_SCHED_SPORADIC + if (policy == SCHED_SPORADIC) + { + FAR struct sporadic_s *sporadic; + int repl_ticks; + int budget_ticks; + + /* Convert timespec values to system clock ticks */ + + (void)clock_time2ticks(¶m.sched_ss_repl_period, &repl_ticks); + (void)clock_time2ticks(¶m.sched_ss_init_budget, &budget_ticks); + + /* The replenishment period must be greater than or equal to the + * budget period. + */ + + if (repl_ticks < budget_ticks) + { + errcode = EINVAL; + goto errout_with_join; + } + + /* Initialize the sporadic policy */ + + ret = sched_sporadic_initialize(&ptcb->cmn); + if (ret >= 0) + { + sporadic = ptcb->cmn.sporadic; + DEBUGASSERT(sporadic != NULL); + + /* Save the sporadic scheduling parameters */ + + sporadic->hi_priority = param.sched_priority; + sporadic->low_priority = param.sched_ss_low_priority; + sporadic->max_repl = param.sched_ss_max_repl; + sporadic->repl_period = repl_ticks; + sporadic->budget = budget_ticks; + + /* And start the first replenishment interval */ + + ret = sched_sporadic_start(&ptcb->cmn); + } + + /* Handle any failures */ + + if (ret < 0) + { + errcode = -ret; + goto errout_with_join; + } + } +#endif + /* Initialize the task control block */ - ret = pthread_schedsetup(ptcb, priority, pthread_start, start_routine); + ret = pthread_schedsetup(ptcb, param.sched_priority, pthread_start, + start_routine); if (ret != OK) { errcode = EBUSY; diff --git a/sched/sched/sched.h b/sched/sched/sched.h index ca83dcfe04..95595b5bcb 100644 --- a/sched/sched/sched.h +++ b/sched/sched/sched.h @@ -246,9 +246,11 @@ uint32_t sched_roundrobin_process(FAR struct tcb_s *tcb, uint32_t ticks, #endif #ifdef CONFIG_SCHED_SPORADIC -int sched_sporadic_start(FAR struct tcb_s *tcb); -int sched_sporadic_stop(FAR struct tcb_s *tcb); -int sched_sporadic_resume(FAR struct tcb_s *tcb); +int sched_sporadic_initialize(FAR struct tcb_s *tcb); +int sched_sporadic_start(FAR struct tcb_s *tcb); +int sched_sporadic_stop(FAR struct tcb_s *tcb); +int sched_sporadic_reset(FAR struct tcb_s *tcb); +int sched_sporadic_resume(FAR struct tcb_s *tcb); uint32_t sched_sporadic_process(FAR struct tcb_s *tcb, uint32_t ticks, bool noswitches); void sched_sporadic_lowpriority(FAR struct tcb_s *tcb); diff --git a/sched/sched/sched_getparam.c b/sched/sched/sched_getparam.c index 82dc406eb2..b42c831603 100644 --- a/sched/sched/sched_getparam.c +++ b/sched/sched/sched_getparam.c @@ -134,22 +134,35 @@ int sched_getparam (pid_t pid, FAR struct sched_param *param) } else { +#ifdef CONFIG_SCHED_SPORADIC +#endif /* Return the priority of the task */ param->sched_priority = (int)tcb->sched_priority; #ifdef CONFIG_SCHED_SPORADIC - /* Return parameters associated with SCHED_SPORADIC */ + if ((tcb->flags & TCB_FLAG_POLICY_MASK) == TCB_FLAG_SCHED_SPORADIC) + { + FAR struct sporadic_s *sporadic = tcb->sporadic; + DEBUGASSERT(sporadic != NULL); - param->sched_ss_low_priority = (int)tcb->low_priority; -#ifdef __REVISIT_REPLENISHMENTS - param->sched_ss_max_repl = (int)tcb->max_repl; -#else - param->sched_ss_max_repl = 1; -#endif + /* Return parameters associated with SCHED_SPORADIC */ - clock_ticks2time((int)tcb->repl_period, ¶m->sched_ss_repl_period); - clock_ticks2time((int)tcb->budget, ¶m->sched_ss_init_budget); + param->sched_ss_low_priority = (int)sporadic->low_priority; + param->sched_ss_max_repl = (int)sporadic->max_repl; + + clock_ticks2time((int)sporadic->repl_period, ¶m->sched_ss_repl_period); + clock_ticks2time((int)sporadic->budget, ¶m->sched_ss_init_budget); + } + else + { + param->sched_ss_low_priority = 0; + param->sched_ss_max_repl = 0; + param->sched_ss_repl_period.tv_sec = 0; + param->sched_ss_repl_period.tv_nsec = 0; + param->sched_ss_init_budget.tv_sec = 0; + param->sched_ss_init_budget.tv_nsec = 0; + } #endif } diff --git a/sched/sched/sched_setparam.c b/sched/sched/sched_setparam.c index e477f05cf8..42bfe06303 100644 --- a/sched/sched/sched_setparam.c +++ b/sched/sched/sched_setparam.c @@ -131,19 +131,35 @@ int sched_setparam(pid_t pid, FAR const struct sched_param *param) if ((rtcb->flags & TCB_FLAG_POLICY_MASK) == TCB_FLAG_SCHED_SPORADIC) { + FAR struct sporadic_s *sporadic; irqstate_t flags; int repl_ticks; int budget_ticks; -#ifdef __REVISIT_REPLENISHMENTS - DEBUGASSERT(param->sched_ss_max_repl <= UINT8_MAX); -#endif + if (param->sched_ss_max_repl < 1 || + param->sched_ss_max_repl > CONFIG_SCHED_SPORADIC_MAXREPL) + { + errcode = EINVAL; + goto errout_with_lock; + } /* Convert timespec values to system clock ticks */ (void)clock_time2ticks(¶m->sched_ss_repl_period, &repl_ticks); (void)clock_time2ticks(¶m->sched_ss_init_budget, &budget_ticks); + /* Avoid zero/negative times */ + + if (repl_ticks < 1) + { + repl_ticks = 1; + } + + if (budget_ticks < 1) + { + budget_ticks = 1; + } + /* The replenishment period must be greater than or equal to the * budget period. */ @@ -157,35 +173,37 @@ int sched_setparam(pid_t pid, FAR const struct sched_param *param) /* Stop/reset current sporadic scheduling */ flags = irqsave(); - DEBUGVERIFY(sched_sporadic_stop(tcb)); + ret = sched_sporadic_reset(tcb); + if (ret >= 0) + { + /* Save the sporadic scheduling parameters and reset to the + * beginning to the replenishment interval. + */ - /* Save the sporadic scheduling parameters and reset to the beginning - * to the replenishment interval. - */ + tcb->timeslice = budget_ticks; - tcb->timeslice = budget_ticks; - tcb->hi_priority = param->sched_priority; - tcb->low_priority = param->sched_ss_low_priority; -#ifdef __REVISIT_REPLENISHMENTS - tcb->max_repl = param->sched_ss_max_repl; -#endif - tcb->repl_period = repl_ticks; - tcb->budget = budget_ticks; + sporadic = rtcb->sporadic; + DEBUGASSERT(sporadic != NULL); - /* And restart at the next replenishment interval */ + sporadic->hi_priority = param->sched_priority; + sporadic->low_priority = param->sched_ss_low_priority; + sporadic->max_repl = param->sched_ss_max_repl; + sporadic->repl_period = repl_ticks; + sporadic->budget = budget_ticks; + + /* And restart at the next replenishment interval */ + + ret = sched_sporadic_start(tcb); + } + + /* Restore interrupts and handler errors */ - DEBUGVERIFY(sched_sporadic_start(tcb)); irqrestore(flags); - } - else - { - tcb->hi_priority = 0; - tcb->low_priority = 0; -#ifdef __REVISIT_REPLENISHMENTS - tcb->max_repl = 0; -#endif - tcb->repl_period = 0; - tcb->budget = 0; + if (ret < 0) + { + errcode = -ret; + goto errout_with_lock; + } } #endif diff --git a/sched/sched/sched_setscheduler.c b/sched/sched/sched_setscheduler.c index 118f71f201..34c5750939 100644 --- a/sched/sched/sched_setscheduler.c +++ b/sched/sched/sched_setscheduler.c @@ -87,6 +87,9 @@ int sched_setscheduler(pid_t pid, int policy, { FAR struct tcb_s *tcb; irqstate_t saved_state; +#ifdef CONFIG_SCHED_SPORADIC + int errcode; +#endif int ret; /* Check for supported scheduling policy */ @@ -175,49 +178,83 @@ int sched_setscheduler(pid_t pid, int policy, #ifdef CONFIG_SCHED_SPORADIC case SCHED_SPORADIC: { + FAR struct sporadic_s *sporadic; int repl_ticks; int budget_ticks; -#ifdef __REVISIT_REPLENISHMENTS - DEBUGASSERT(param->sched_ss_max_repl <= UINT8_MAX); -#endif + if (param->sched_ss_max_repl < 1 || + param->sched_ss_max_repl > CONFIG_SCHED_SPORADIC_MAXREPL) + { + errcode = EINVAL; + goto errout_with_irq; + } /* Convert timespec values to system clock ticks */ (void)clock_time2ticks(¶m->sched_ss_repl_period, &repl_ticks); (void)clock_time2ticks(¶m->sched_ss_init_budget, &budget_ticks); + /* Avoid zero/negative times */ + + if (repl_ticks < 1) + { + repl_ticks = 1; + } + + if (budget_ticks < 1) + { + budget_ticks = 1; + } + /* The replenishment period must be greater than or equal to the * budget period. */ if (repl_ticks < budget_ticks) { - set_errno(EINVAL); - irqrestore(saved_state); - sched_unlock(); - return ERROR; + errcode = EINVAL; + goto errout_with_irq; } - /* Stop/reset current sporadic scheduling */ + /* Initialize/reset current sporadic scheduling */ - DEBUGVERIFY(sched_sporadic_stop(tcb)); + if ((tcb->flags & TCB_FLAG_POLICY_MASK) == TCB_FLAG_SCHED_SPORADIC) + { + ret = sched_sporadic_reset(tcb); + } + else + { + ret = sched_sporadic_initialize(tcb); + } /* Save the sporadic scheduling parameters. */ - tcb->flags |= TCB_FLAG_SCHED_SPORADIC; - tcb->timeslice = budget_ticks; - tcb->hi_priority = param->sched_priority; - tcb->low_priority = param->sched_ss_low_priority; -#ifdef __REVISIT_REPLENISHMENTS - tcb->max_repl = param->sched_ss_max_repl; -#endif - tcb->repl_period = repl_ticks; - tcb->budget = budget_ticks; + if (ret >= 0) + { + tcb->flags |= TCB_FLAG_SCHED_SPORADIC; + tcb->timeslice = budget_ticks; - /* And restart at the next replenishment interval */ + sporadic = tcb->sporadic; + DEBUGASSERT(sporadic != NULL); - DEBUGVERIFY(sched_sporadic_start(tcb)); + sporadic->hi_priority = param->sched_priority; + sporadic->low_priority = param->sched_ss_low_priority; + sporadic->max_repl = param->sched_ss_max_repl; + sporadic->repl_period = repl_ticks; + sporadic->budget = budget_ticks; + + /* And restart at the next replenishment interval */ + + ret = sched_sporadic_start(tcb); + } + + /* Handle errors */ + + if (ret < 0) + { + errcode = -ret; + goto errout_with_irq; + } } break; #endif @@ -236,4 +273,12 @@ int sched_setscheduler(pid_t pid, int policy, ret = sched_reprioritize(tcb, param->sched_priority); sched_unlock(); return (ret >= 0) ? OK : ERROR; + +#ifdef CONFIG_SCHED_SPORADIC +errout_with_irq: + set_errno(errcode); + irqrestore(saved_state); + sched_unlock(); + return ERROR; +#endif } diff --git a/sched/sched/sched_sporadic.c b/sched/sched/sched_sporadic.c index 8982817e6f..c392fba4ef 100644 --- a/sched/sched/sched_sporadic.c +++ b/sched/sched/sched_sporadic.c @@ -1,4 +1,4 @@ -/************************************************************************ +/**************************************************************************** * sched/sched/sched_sporadic.c * * Copyright (C) 2015 Gregory Nutt. All rights reserved. @@ -31,11 +31,11 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * - ************************************************************************/ + ****************************************************************************/ -/************************************************************************ +/**************************************************************************** * Included Files - ************************************************************************/ + ****************************************************************************/ #include @@ -55,45 +55,65 @@ #ifdef CONFIG_SCHED_SPORADIC -/************************************************************************ +/**************************************************************************** * Pre-processor Definitions - ************************************************************************/ + ****************************************************************************/ #ifndef MIN # define MIN(a,b) (((a) < (b)) ? (a) : (b)) #endif -/************************************************************************ - * Private Functions - ************************************************************************/ +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ -/************************************************************************ - * Name: sched_sporadic_replenish_start +static int sporadic_budget_start(FAR struct tcb_s *tcb, + FAR struct replenishment_s *repl, uint32_t budget); +static int sporadic_budget_next(FAR struct replenishment_s *repl); +static int sporadic_interval_start(FAR struct replenishment_s *repl); +static void sporadic_budget_expire(int argc, wdparm_t arg1, ...); +static void sporadic_interval_expire(int argc, wdparm_t arg1, ...); +FAR struct replenishment_s * + sporadic_alloc_repl(FAR struct sporadic_s *sporadic); + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sporadic_budget_start * * Description: - * Start the next replenishment cycle, increasing the priority of the - * thread to the high priority. This is normally a pretty trivial - * operation. But we do have to take a few precautions is priority - * inheritance is enabled. + * Start the next replenishment cycle by (1) increasing the priority of + * the thread to the high priority and (2) setting up a timer for the + * budgeted portion of the replenishment interval. We do have to take a + * few precautions is priority inheritance is enabled. * - * Parameters: - * tcb - TCB of the thread whose priority is being boosted. + * Input Parameters: + * tcb - TCB of the thread whose priority is being boosted. + * repl - The replenishment timer to use + * budget - Budgeted execution time * * Returned Value: * Returns zero (OK) on success or a negated errno value on failure. * - ************************************************************************/ + ****************************************************************************/ -static int sched_sporadic_replenish_start(FAR struct tcb_s *tcb) +static int sporadic_budget_start(FAR struct tcb_s *tcb, + FAR struct replenishment_s *repl, + uint32_t budget) { + FAR struct sporadic_s *sporadic; int ret; + DEBUGASSERT(tcb && tcb->sporadic); + sporadic = tcb->sporadic; + /* Start the next replenishment interval */ - tcb->timeslice = tcb->budget; -#ifdef __REVISIT_REPLENISHMENTS - tcb->nrepl = tcb->max_repl; -#endif + tcb->timeslice = budget; + ret = wd_start(&repl->timer, sporadic->budget, sporadic_budget_expire, + 1, (wdentry_t)sporadic); #ifdef CONFIG_PRIORITY_INHERITANCE /* If the priority was boosted above the higher priority, than just @@ -104,13 +124,13 @@ static int sched_sporadic_replenish_start(FAR struct tcb_s *tcb) { /* Boosted... Do we still need to reprioritize? */ - if (tcb->hi_priority < tcb->base_priority) + if (sporadic->hi_priority < sporadic->base_priority) { /* No.. the current execution priority is lower than the * boosted priority. Just reset the base priority. */ - tcb->base_priority = tcb->hi_priority; + tcb->base_priority = sporadic->hi_priority; return OK; } } @@ -124,7 +144,7 @@ static int sched_sporadic_replenish_start(FAR struct tcb_s *tcb) /* Then reprioritize to the higher priority */ - ret = sched_reprioritize(tcb, tcb->hi_priority); + ret = sched_reprioritize(tcb, sporadic->hi_priority); if (ret < 0) { return -get_errno(); @@ -133,14 +153,194 @@ static int sched_sporadic_replenish_start(FAR struct tcb_s *tcb) return OK; } -/************************************************************************ - * Name: sched_sporadic_expire +/**************************************************************************** + * Name: sporadic_budget_next * * Description: - * Handles the expiration of a replenishment interval by starting the - * next replenishment interval. + * Start the next replenishment. This is called at the complete of each + * replenishment interval. * - * Parameters: + * Input Parameters: + * repl - Replenishment structure whose budget timer just expired. + * + * Returned Value: + * Returns zero (OK) on success or a negated errno value on failure. + * + ****************************************************************************/ + +static int sporadic_budget_next(FAR struct replenishment_s *repl) +{ + FAR struct sporadic_s *sporadic; + FAR struct tcb_s *tcb; + uint32_t budget; + + DEBUGASSERT(repl != NULL && repl->tcb != NULL); + tcb = repl->tcb; + sporadic = tcb->sporadic; + DEBUGASSERT(sporadic != NULL); + + /* The budgeted interval will be the pending budget */ + + budget = sporadic->pending; + if (budget > sporadic->budget) + { + /* Clip to the maximum */ + + budget = sporadic->budget; + } + + sporadic->pending -= budget; + + /* If the budget zero, then all of the pending budget has been utilized. + * There are now two possibilities: (1) There are multiple, active + * replenishment threads so this one is no longer needed, or (2) there is + * only one and we need to restart the budget interval with the full + * budget. + */ + + if (budget == 0) + { + if (sporadic->nrepls > 1) + { + /* Release this replenishment timer. Processing will continue + * to be driven by the remaining timers. + */ + + repl->active = false; + sporadic->nrepls--; + return OK; + } + else + { + /* No, we are the only replenishment timer. Restart with the + * full budget. + */ + + budget = sporadic->budget; + } + } + + /* Start the next replenishment interval */ + + return sporadic_budget_start(tcb, repl, budget); +} + +/**************************************************************************** + * Name: sporadic_set_lowpriority + * + * Description: + * Force the thread to lower priority. + * + * Input Parameters: + * repl - Replenishment timer to be used + * + * Returned Value: + * Returns zero (OK) on success or a negated errno value on failure. + * + ****************************************************************************/ + +static int sporadic_set_lowpriority(FAR struct tcb_s *tcb) +{ + FAR struct sporadic_s *sporadic; + int ret; + + DEBUGASSERT(tcb != NULL && tcb->sporadic != NULL); + sporadic = tcb->sporadic; + +#ifdef CONFIG_PRIORITY_INHERITANCE + /* If the priority was boosted above the higher priority, than just + * reset the base priority. + */ + + if (tcb->sched_priority > tcb->base_priority) + { + /* Thread priority was boosted while we were in the high priority + * state. + */ + + tcb->base_priority = sporadic->low_priority; + } +#endif + + /* Otherwise drop the priority of thread, possible causing a context + * switch. + */ + + ret = sched_reprioritize(tcb, sporadic->low_priority); + if (ret < 0) + { + return -get_errno(); + } + + return OK; +} + +/**************************************************************************** + * Name: sporadic_interval_start + * + * Description: + * Start the next replenishment cycle, increasing the priority of the + * thread to the high priority. This is normally a pretty trivial + * operation. But we do have to take a few precautions is priority + * inheritance is enabled. + * + * Input Parameters: + * repl - Replenishment timer to be used + * + * Returned Value: + * Returns zero (OK) on success or a negated errno value on failure. + * + ****************************************************************************/ + +static int sporadic_interval_start(FAR struct replenishment_s *repl) +{ + FAR struct sporadic_s *sporadic; + FAR struct tcb_s *tcb; + uint32_t remainder; + + DEBUGASSERT(repl != NULL && repl->tcb != NULL); + tcb = repl->tcb; + sporadic = tcb->sporadic; + DEBUGASSERT(sporadic != NULL); + + /* Enter the low-priority phase of the replenishment cycle */ + + tcb->timeslice = 0; + + /* Calculate the remainder of the replenishment interval. This is + * permitted to be zero, in which case we just restart the budget + * interval without lowering the priority. + */ + + DEBUGASSERT(sporadic->repl_period >= sporadic->budget); + remainder = sporadic->repl_period - sporadic->budget; + if (remainder == 0) + { + return sporadic_budget_next(repl); + } + + /* Start the timer that will terminate the low priority cycle. This timer + * expiration is independent of what else may occur (except that it must + * be cancelled if the thread exits. + */ + + DEBUGVERIFY(wd_start(&repl->timer, remainder, sporadic_interval_expire, + 1, (wdentry_t)repl)); + + /* Drop the priority of thread, possible causing a context switch. */ + + return sporadic_set_lowpriority(tcb); +} + +/**************************************************************************** + * Name: sporadic_budget_expire + * + * Description: + * Handles the expiration of a budget interval. It saves the budget + * For the next interval, drops the priority of the thread, and restarts + * the timer for the rest of the replenishment period. + * + * Input Parameters: * Standard watchdog parameters * * Returned Value: @@ -150,24 +350,230 @@ static int sched_sporadic_replenish_start(FAR struct tcb_s *tcb) * The thread is still running and is still using the sporadic * scheduling policy. * - ************************************************************************/ + ****************************************************************************/ -static void sched_sporadic_expire(int argc, wdparm_t arg1, ...) +static void sporadic_budget_expire(int argc, wdparm_t arg1, ...) { - FAR struct tcb_s *tcb = (FAR struct tcb_s *)arg1; + FAR struct replenishment_s *repl = (FAR struct replenishment_s *)arg1; + FAR struct sporadic_s *sporadic; + FAR struct tcb_s *tcb; + uint32_t pending; - DEBUGASSERT(argc == 1 && tcb != NULL); + DEBUGASSERT(argc == 1 && repl != NULL && repl->tcb != NULL); + tcb = repl->tcb; + + sporadic = tcb->sporadic; + DEBUGASSERT(sporadic != NULL); + + /* As a special case, we can do nothing here if schedule has been locked. + * We cannot drop the priority because that might cause a context switch, + * violating the lock. + * + * What we do instead is just deallocate the timer. When the lock is + * finally released, sched_sporadic_lowpriority() and that will restart + * the interval period. timeslice == -1 is the cue to sched_unlock() that + * this operation is needed. + */ + + if (tcb->lockcount > 0) + { + DEBUGASSERT(repl->active && sporadic->nrepls > 0); + tcb->timeslice = -1; + repl->active = false; + sporadic->nrepls--; + return; + } + + /* Calculate any part of the budget that was not utilized */ + + DEBUGASSERT(sporadic->budget >= tcb->timeslice); + pending = sporadic->pending + sporadic->budget - tcb->timeslice; + if (pending > sporadic->budget) + { + /* Limit to the full budget. This can happen if we are falling + * behind and the thread is not getting enough CPU bandwidth to + * satisfy its budget. + */ + + pending = sporadic->budget; + } + + sporadic->pending = pending; + + /* Drop the priority of the thread and start the timer for the rest of the interval */ + + DEBUGVERIFY(sporadic_interval_start(repl)); +} + +/**************************************************************************** + * Name: sporadic_interval_expire + * + * Description: + * Handles the expiration of a replenishment interval by starting the + * next replenishment interval. + * + * Input Parameters: + * Standard watchdog parameters + * + * Returned Value: + * None + * + * Assumptions: + * The thread is still running and is still using the sporadic + * scheduling policy. + * + ****************************************************************************/ + +static void sporadic_interval_expire(int argc, wdparm_t arg1, ...) +{ + FAR struct replenishment_s *repl = (FAR struct replenishment_s *)arg1; + + DEBUGASSERT(argc == 1 && repl != NULL); /* Start the next replenishment interval */ - DEBUGVERIFY(sched_sporadic_replenish_start(tcb)); + DEBUGVERIFY(sporadic_budget_next(repl)); } -/************************************************************************ - * Public Functions - ************************************************************************/ +/**************************************************************************** + * Name: sporadic_timer_cancel + * + * Description: + * Cancel all timers. We do this if/when the budget time expires while the + * scheduler is locked. Basically we need to stop everything and restart + * when the scheduler is unlocked. + * + * Input Parameters: + * tcb - The TCB of the thread that has the scheduler locked + * + * Returned Value: + * None + * + ****************************************************************************/ -/************************************************************************ +static void sporadic_timer_cancel(FAR struct tcb_s *tcb) +{ + FAR struct sporadic_s *sporadic; + FAR struct replenishment_s *repl; + int i; + + DEBUGASSERT(tcb && tcb->sporadic); + sporadic = tcb->sporadic; + + /* Cancel all timers. */ + + for (i = 0; i < CONFIG_SCHED_SPORADIC_MAXREPL; i++) + { + repl = &sporadic->replenishments[i]; + + /* Cancel any outstanding timer activity */ + + wd_cancel(&repl->timer); + repl->active = false; + } + + sporadic->nrepls = 0; +} + +/**************************************************************************** + * Name: sporadic_alloc_repl + * + * Description: + * Allocate a replenishment timer structure. + * + * Input Parameters: + * sporadic - The task's sporadic scheduling state. + * + * Returned Value: + * The allocated replenishment timer structure; NULL is returned on a failure + * + ****************************************************************************/ + +FAR struct replenishment_s * + sporadic_alloc_repl(FAR struct sporadic_s *sporadic) +{ + FAR struct replenishment_s *repl = NULL; + int i; + + if (sporadic->nrepls < sporadic->max_repl) + { + /* Allocate a new replenishment timer */ + + DEBUGASSERT(sporadic->max_repl <= CONFIG_SCHED_SPORADIC_MAXREPL); + for (i = 0; i < sporadic->max_repl; i++) + { + FAR struct replenishment_s *tmp = &sporadic->replenishments[i]; + if (!tmp->active) + { + repl = tmp; + repl->active = true; + sporadic->nrepls++; + break; + } + } + + /* Since we no that we have not yet reached the max_repl number of + * timers, the above search should never fail. + */ + + DEBUGASSERT(repl != NULL); + } + + return repl; +} + + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sched_sporadic_initialize + * + * Description: + * Allocate resources needed by the sporadic scheduling policy. + * + * Input Parameters: + * tcb - TCB of the thread whose priority is being boosted. + * + * Returned Value: + * Returns zero (OK) on success or a negated errno value on failure. + * + ****************************************************************************/ + +int sched_sporadic_initialize(FAR struct tcb_s *tcb) +{ + FAR struct sporadic_s *sporadic; + int i; + + DEBUGASSERT(tcb != NULL && tcb->sporadic == NULL); + + /* Allocate the sporadic add-on data structure that will hold the + * sporadic scheduling parameters and state data. + */ + + sporadic = (FAR struct sporadic_s *)kmm_zalloc(sizeof(struct sporadic_s)); + if (sporadic == NULL) + { + return -ENOMEM; + } + + /* The initialize required is to set the back pointer to the TCB in + * each of the replenishment structures. + */ + + for (i = 0; i < CONFIG_SCHED_SPORADIC_MAXREPL; i++) + { + sporadic->replenishments[i].tcb = tcb; + } + + /* Hook the sporadic add-on into the TCB */ + + tcb->sporadic = sporadic; + return OK; +} + +/**************************************************************************** * Name: sched_sporadic_start * * Description: @@ -176,12 +582,12 @@ static void sched_sporadic_expire(int argc, wdparm_t arg1, ...) * * - When starting a pthread with sporadic scheduling specified in * the pthread attributes. - * - When establishing sporadic scheduling policy via + * - When establishing sporadic scheduling policy via * sched_setscheduler() * - When the sporadic scheduling parameters are changed via * sched_setparam(). * - * Parameters: + * Input Parameters: * tcb - The TCB of the thread that is beginning sporadic scheduling. * * Returned Value: @@ -192,38 +598,44 @@ static void sched_sporadic_expire(int argc, wdparm_t arg1, ...) * - All sporadic scheduling parameters in the TCB are valid * - The thread is not currently using the sporadic scheduliing policy. * - ************************************************************************/ + ****************************************************************************/ int sched_sporadic_start(FAR struct tcb_s *tcb) { - DEBUGASSERT(tcb); + FAR struct sporadic_s *sporadic; + FAR struct replenishment_s *repl; - /* Cancel and pending low-priority interval timing and re-initialize - * the watchdog timer. - */ + DEBUGASSERT(tcb && tcb->sporadic); + sporadic = tcb->sporadic; - wd_cancel(&tcb->low_dog); - memset(&tcb->low_dog, 0, sizeof(struct wdog_s)); + DEBUGASSERT(sporadic->low_priority <= sporadic->hi_priority); + DEBUGASSERT(sporadic->max_repl <= CONFIG_SCHED_SPORADIC_MAXREPL); + DEBUGASSERT(sporadic->budget > 0 && sporadic->budget <= sporadic->repl_period); + DEBUGASSERT(sporadic->nrepls == 0 && sporadic->pending == 0); - /* Then start the first replenishment interval */ + /* Allocate the first replenishment timer (should never fail) */ - return sched_sporadic_replenish_start(tcb); + repl = sporadic_alloc_repl(sporadic); + DEBUGASSERT(repl != NULL && sporadic->nrepls == 1); + + /* Then start the first interval */ + + return sporadic_budget_start(tcb, repl, sporadic->budget); } -/************************************************************************ +/**************************************************************************** * Name: sched_sporadic_stop * * Description: - * Called to terminate sporadic scheduling on a given thread. This - * function is called in the following circumstances: + * Called to terminate sporadic scheduling on a given thread and to + * free all resources associated with the policy. This function is + * called in the following circumstances: * * - When any thread exits with sporadic scheduling active. * - When any thread using sporadic scheduling is changed to use * some other scheduling policy via sched_setscheduler() - * - When the sporadic scheduling parameters are changed via - * sched_setparam(). * - * Parameters: + * Input Parameters: * tcb - The TCB of the thread that is beginning sporadic scheduling. * * Returned Value: @@ -234,34 +646,84 @@ int sched_sporadic_start(FAR struct tcb_s *tcb) * - All sporadic scheduling parameters in the TCB are valid * - The thread is currently using the sporadic scheduling policy. * - ************************************************************************/ + ****************************************************************************/ int sched_sporadic_stop(FAR struct tcb_s *tcb) { - DEBUGASSERT(tcb); + DEBUGASSERT(tcb && tcb->sporadic); - /* Cancel and pending low-priority interval timing and re-initialize - * the watchdog timer. - */ + /* Stop all timers, reset scheduling */ - wd_cancel(&tcb->low_dog); - memset(&tcb->low_dog, 0, sizeof(struct wdog_s)); + (void)sched_sporadic_reset(tcb); - /* Reset sporadic scheduling parameters */ + /* The free the container holder the sporadic scheduling parameters */ - tcb->hi_priority = 0; - tcb->low_priority = 0; -#ifdef __REVISIT_REPLENISHMENTS - tcb->max_repl = 0; - tcb->nrepl = 0; -#endif - tcb->timeslice = 0; - tcb->repl_period = 0; - tcb->budget = 0; + kmm_free(tcb->sporadic); + tcb->sporadic = NULL; return OK; } -/************************************************************************ +/**************************************************************************** + * Name: sched_sporadic_reset + * + * Description: + * Called to stop sporadic scheduling on a given thread. This + * function is called in the following circumstances: + * + * - When the sporadic scheduling parameters are changed via + * sched_setparam() + * - From sched_sporadic_stop when under those conditions. + * + * Input Parameters: + * tcb - The TCB of the thread that is beginning sporadic scheduling. + * + * Returned Value: + * Returns zero (OK) on success or a negated errno value on failure. + * + * Assumptions: + * - Interrupts are disabled + * - All sporadic scheduling parameters in the TCB are valid + * - The thread is currently using the sporadic scheduling policy. + * + ****************************************************************************/ + +int sched_sporadic_reset(FAR struct tcb_s *tcb) +{ + FAR struct sporadic_s *sporadic; + FAR struct replenishment_s *repl; + int i; + + DEBUGASSERT(tcb && tcb->sporadic); + sporadic = tcb->sporadic; + + /* Cancel all timers. */ + + for (i = 0; i < CONFIG_SCHED_SPORADIC_MAXREPL; i++) + { + repl = (FAR struct replenishment_s *)&sporadic->replenishments[i]; + + /* Cancel any outstanding timer activity */ + + wd_cancel(&repl->timer); + + /* Re-initialize replenishment data */ + + repl->tcb = tcb; + } + + /* Reset sporadic scheduling parameters and state data */ + + sporadic->hi_priority = 0; + sporadic->low_priority = 0; + sporadic->max_repl = 0; + sporadic->nrepls = 0; + sporadic->repl_period = 0; + sporadic->budget = 0; + sporadic->pending = 0; + return OK; +} + +/**************************************************************************** * Name: sched_sporadic_resume * * Description: @@ -274,7 +736,7 @@ int sched_sporadic_stop(FAR struct tcb_s *tcb) * This function does nothing if the budget phase as already elapsed or * the maximum numer of replenishments have already been performed. * - * Parameters: + * Input Parameters: * tcb - The TCB of the thread that is beginning sporadic scheduling. * * Returned Value: @@ -285,37 +747,40 @@ int sched_sporadic_stop(FAR struct tcb_s *tcb) * - All sporadic scheduling parameters in the TCB are valid * - The low priority interval timer is not running * - ************************************************************************/ + ****************************************************************************/ int sched_sporadic_resume(FAR struct tcb_s *tcb) { - DEBUGASSERT(tcb); + FAR struct sporadic_s *sporadic; + FAR struct replenishment_s *repl; + uint32_t budget; - /* REVISIT: This logic is wrong. In order to correctly implement - * replenishments, we would need to add: (1) logic to keep more - * accurate accounting of the expended budget execution time, and (2) - * multiple timers to handle the nested replenishment intervals. - * - * The logic here works as is but effective max_repl == 1. + DEBUGASSERT(tcb && tcb->sporadic); + sporadic = tcb->sporadic; + + /* Check if are in the budget portion of the replenishment interval. We + * know this is the case if the current timeslice is non-zero. Do not + * exceed the maximum number of replenishments. */ -#ifdef __REVISIT_REPLENISHMENTS - /* Make sure that we are in the budget portion of the replenishment - * interval. We know this is the case if the current timeslice is - * non-zero. Do not exceed the maximum number of replenishments. - */ - - if (tcb->timeslice > 0 && tcb->nrepl > 0) + if (tcb->timeslice > 0) { - tcb->timeslice = tcb->budget; - tcb->nrepl--; + /* Allocate a new replenishment timer */ + + repl = sporadic_alloc_repl(sporadic); + if (repl) + { + budget = tcb->timeslice; + return sporadic_budget_start(tcb, repl, budget); + } + + return -ENOMEM; } -#endif return OK; } -/************************************************************************ +/**************************************************************************** * Name: sched_sporadic_process * * Description: @@ -324,26 +789,31 @@ int sched_sporadic_resume(FAR struct tcb_s *tcb) * - From the timer interrupt handler while the thread with sporadic * scheduling is running. * - * Parameters: - * tcb - The TCB of the thread that is beginning sporadic scheduling. - * ticks - The number of elapsed ticks since the last time this - * function was called. + * Input Parameters: + * tcb - The TCB of the thread that is beginning sporadic + scheduling. + * ticks - The number of elapsed ticks since the last time this + * function was called. + * noswitches - We are running in a context where context switching is + * not permitted. * * Returned Value: * The number if ticks remaining until the budget interval expires. - * Zero is returned if we are in the low-prioriy phase of the the + * Zero is returned if we are in the low-priority phase of the the * replenishment interval. * * Assumptions: * - Interrupts are disabled * - All sporadic scheduling parameters in the TCB are valid * - ************************************************************************/ + ****************************************************************************/ uint32_t sched_sporadic_process(FAR struct tcb_s *tcb, uint32_t ticks, bool noswitches) { - DEBUGASSERT(tcb && ticks > 0); + FAR struct sporadic_s *sporadic; + + DEBUGASSERT(tcb != NULL && tcb->sporadic != NULL && ticks > 0); /* If we are in the low-priority phase of the replenishment interval, * then just return zero. @@ -366,7 +836,7 @@ uint32_t sched_sporadic_process(FAR struct tcb_s *tcb, uint32_t ticks, * if there ever were the case. * * Notice that in the case where were are stuck in the high priority - * phase with scheduler locke, timeslice will by -1 and any value of + * phase with scheduler locked, timeslice will by -1 and any value of * ticks will pass this test. */ @@ -384,10 +854,11 @@ uint32_t sched_sporadic_process(FAR struct tcb_s *tcb, uint32_t ticks, * case. */ + sporadic_timer_cancel(tcb); tcb->timeslice = -1; return 0; } - + /* We will also suppress context switches if we were called via one of * the unusual cases handled by sched_timer_reasses(). In that case, * we will return a value of one so that the timer will expire as soon @@ -410,15 +881,16 @@ uint32_t sched_sporadic_process(FAR struct tcb_s *tcb, uint32_t ticks, * thing to do, but is certainly permitted. */ - if (tcb->budget >= tcb->repl_period) + sporadic = tcb->sporadic; + if (sporadic->budget >= sporadic->repl_period) { - tcb->timeslice = tcb->budget; - return tcb->budget; + tcb->timeslice = sporadic->budget; + return sporadic->budget; } /* Otherwise enter the low-priority phase of the replenishment cycle */ - sched_sporadic_lowpriority(tcb); + sporadic_set_lowpriority(tcb); return 0; } @@ -433,7 +905,7 @@ uint32_t sched_sporadic_process(FAR struct tcb_s *tcb, uint32_t ticks, } } -/************************************************************************ +/**************************************************************************** * Name: sched_sporadic_lowpriority * * Description: @@ -444,8 +916,9 @@ uint32_t sched_sporadic_process(FAR struct tcb_s *tcb, uint32_t ticks, * - sched_unlock(). When the budget expires while the thread had the * scheduler locked. * - * Parameters: - * tcb - The TCB of the thread that is entering the low priority phase. + * Input Parameters: + * tcb - The TCB of the thread that is entering the low priority phase. + * restart - Restart timers. * * Returned Value: * None @@ -454,44 +927,31 @@ uint32_t sched_sporadic_process(FAR struct tcb_s *tcb, uint32_t ticks, * - Interrupts are disabled * - All sporadic scheduling parameters in the TCB are valid * - ************************************************************************/ + ****************************************************************************/ void sched_sporadic_lowpriority(FAR struct tcb_s *tcb) { - DEBUGASSERT(tcb); + FAR struct sporadic_s *sporadic; + FAR struct replenishment_s *repl; - /* Enter the low-priority phase of the replenishment cycle */ + DEBUGASSERT(tcb && tcb->sporadic); + sporadic = tcb->sporadic; + + /* Enter the low-priority phase of the replenishment cycle. */ tcb->timeslice = 0; - /* Start the timer that will terminate the low priority cycle. This timer - * expiration is independent of what else may occur (except that it must - * be cancelled if the thread exits. + /* Allocate a new replenishment timer. There should be no timers + * active at this phase since they were stopped in sched_sporadic_process(). */ - DEBUGVERIFY(wd_start(&tcb->low_dog, tcb->repl_period - tcb->budget, - sched_sporadic_expire, 1, (wdentry_t)tcb)); + DEBUGASSERT(sporadic->nrepls < sporadic->max_repl); + repl = sporadic_alloc_repl(sporadic); + DEBUGASSERT(repl != NULL); -#ifdef CONFIG_PRIORITY_INHERITANCE - /* If the priority was boosted above the higher priority, than just - * reset the base priority. - */ + /* Drop the priority of thread, possible causing a context switch. */ - if (tcb->sched_priority > tcb->base_priority) - { - /* Thread priority was boosted while we were in the high priority - * state. - */ - - tcb->base_priority = tcb->low_priority; - } -#endif - - /* Otherwise drop the priority of thread, possible causing a context - * switch. - */ - - DEBUGVERIFY(sched_reprioritize(tcb, tcb->low_priority)); + DEBUGVERIFY(sporadic_interval_start(repl)); } #endif /* CONFIG_SCHED_SPORADIC */ diff --git a/sched/sched/sched_timerexpiration.c b/sched/sched/sched_timerexpiration.c index c078328d8c..be409c3492 100644 --- a/sched/sched/sched_timerexpiration.c +++ b/sched/sched/sched_timerexpiration.c @@ -76,7 +76,7 @@ #if CONFIG_RR_INTERVAL > 0 # define KEEP_ALIVE_TICKS MSEC2TICK(CONFIG_RR_INTERVAL) #else -# define KEEP_ALIVE_TICKS MSEC2TICK(50) +# define KEEP_ALIVE_TICKS MSEC2TICK(80) #endif #ifndef MIN