diff --git a/include/nuttx/sched.h b/include/nuttx/sched.h index 74a44d3fe0..83149aca09 100644 --- a/include/nuttx/sched.h +++ b/include/nuttx/sched.h @@ -271,7 +271,8 @@ struct sporadic_s 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 */ + uint32_t current; /* Unrealized, current budget time */ + uint32_t pending; /* Unrealized, pending execution budget */ /* This is the list of replenishment intervals */ @@ -769,8 +770,9 @@ void task_vforkabort(FAR struct task_tcb_s *child, int errcode); * Name: sched_resume_scheduler * * Description: - * Called by architecture specific implementation of up_unblock_task() in - * order to prepare the scheduler for the thread that is about to be restarted. + * Called by architecture specific implementations that block task execution. + * This function prepares the scheduler for the thread that is about to be + * restarted. * * Input Parameters: * tcb - The TCB of the thread to be restarted. @@ -786,6 +788,26 @@ void sched_resume_scheduler(FAR struct tcb_s *tcb); # define sched_resume_scheduler(tcb) #endif +/******************************************************************************** + * Name: sched_suspend_scheduler + * + * Description: + * Called by architecture specific implementations the start task execution. + * This function performs scheduler operations for the thread that is about to + * be suspended. + * + * Input Parameters: + * tcb - The TCB of the thread to be restarted. + * + * Returned Value: + * None + * + ********************************************************************************/ + +/* Just a place-holder for now */ + +#define sched_suspend_scheduler(tcb) + #undef EXTERN #if defined(__cplusplus) } diff --git a/sched/sched/sched_resumescheduler.c b/sched/sched/sched_resumescheduler.c index 95a08c9d3b..62f3ed2758 100644 --- a/sched/sched/sched_resumescheduler.c +++ b/sched/sched/sched_resumescheduler.c @@ -1,7 +1,7 @@ -/************************************************************************ +/**************************************************************************** * sched/sched/sched_resumescheduler.c * - * Copyright (C) 2007, 2009 Gregory Nutt. All rights reserved. + * Copyright (C) 2015 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -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 @@ -48,16 +48,17 @@ #if CONFIG_RR_INTERVAL > 0 || defined(CONFIG_SCHED_SPORADIC) -/************************************************************************ - * Global Functions - ************************************************************************/ +/**************************************************************************** + * Public Functions + ****************************************************************************/ -/******************************************************************************** +/**************************************************************************** * Name: sched_resume_scheduler * * Description: - * Called by architecture specific implementation of up_unblock_task() in - * order to prepare the scheduler for the thread that is about to be restarted. + * Called by architecture specific implementations that block task + * execution. This function prepares the scheduler for the thread that is + * about to be restarted. * * Input Parameters: * tcb - The TCB of the thread to be restarted. @@ -65,7 +66,7 @@ * Returned Value: * None * - ********************************************************************************/ + ****************************************************************************/ void sched_resume_scheduler(FAR struct tcb_s *tcb) { diff --git a/sched/sched/sched_sporadic.c b/sched/sched/sched_sporadic.c index 43621f68c7..8247049975 100644 --- a/sched/sched/sched_sporadic.c +++ b/sched/sched/sched_sporadic.c @@ -112,8 +112,10 @@ static int sporadic_budget_start(FAR struct tcb_s *tcb, /* Start the next replenishment interval */ tcb->timeslice = budget; - ret = wd_start(&repl->timer, sporadic->budget, sporadic_budget_expire, - 1, (wdentry_t)repl); + tcb->current = budget; + + ret = wd_start(&repl->timer, budget, sporadic_budget_expire, 1, + (wdentry_t)repl); #ifdef CONFIG_PRIORITY_INHERITANCE /* If the priority was boosted above the higher priority, than just @@ -310,6 +312,7 @@ static int sporadic_interval_start(FAR struct replenishment_s *repl) /* Enter the low-priority phase of the replenishment cycle */ tcb->timeslice = 0; + tcb->current = 0; /* Calculate the remainder of the replenishment interval. This is * permitted to be zero, in which case we just restart the budget @@ -382,16 +385,23 @@ static void sporadic_budget_expire(int argc, wdparm_t arg1, ...) if (tcb->lockcount > 0) { DEBUGASSERT(repl->active && sporadic->nrepls > 0); - tcb->timeslice = -1; - repl->active = false; + + tcb->timeslice = -1; + sporadic->current = 0; + repl->active = false; sporadic->nrepls--; return; } - /* Calculate any part of the budget that was not utilized */ + /* Calculate any part of the budget that was not utilized. + * + * current = The initial budget at the beginning of the interval. + * timeslice = The unused part of that budget when the thread did + * not execute. + */ - DEBUGASSERT(sporadic->budget >= tcb->timeslice); - pending = sporadic->pending + sporadic->budget - tcb->timeslice; + DEBUGASSERT(sporadic->current >= tcb->timeslice); + pending = sporadic->pending + sporadic->current - tcb->timeslice; if (pending > sporadic->budget) { /* Limit to the full budget. This can happen if we are falling @@ -601,7 +611,7 @@ int sched_sporadic_initialize(FAR struct tcb_s *tcb) * Assumptions: * - Interrupts are disabled * - All sporadic scheduling parameters in the TCB are valid - * - The thread is not currently using the sporadic scheduliing policy. + * - The thread is not currently using the sporadic scheduling policy. * ****************************************************************************/ @@ -724,6 +734,7 @@ int sched_sporadic_reset(FAR struct tcb_s *tcb) sporadic->nrepls = 0; sporadic->repl_period = 0; sporadic->budget = 0; + sporadic->current = 0; sporadic->pending = 0; return OK; } @@ -758,25 +769,33 @@ int sched_sporadic_resume(FAR struct tcb_s *tcb) { FAR struct sporadic_s *sporadic; FAR struct replenishment_s *repl; - uint32_t budget; 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. + * know this is the case if the current timeslice is non-zero. + * + * This function could also be called before the budget period has had a + * chance to run, i.e., when the value of timeslice has not been decremented + * and is still equal to the initial value. + * + * This latter case could occur if the thread has never had a chance to + * run and is also very likely when the thread is just restarted after + * raising its priority at the beginning of the budget period. We would + * not want to start a new timer in these cases. */ - if (tcb->timeslice > 0) + if (tcb->timeslice > 0 && tcb->timeslice < sporadic->current) { - /* Allocate a new replenishment timer */ + /* Allocate a new replenishment timer. This will limit us to + * to maximum number of replenishments (max_repl). + */ repl = sporadic_alloc_repl(sporadic); if (repl != NULL) { - budget = tcb->timeslice; - return sporadic_budget_start(tcb, repl, budget); + return sporadic_budget_start(tcb, repl, tcb->timeslice); } /* We need to return success even on a failure to allocate. Doing @@ -784,8 +803,7 @@ int sched_sporadic_resume(FAR struct tcb_s *tcb) * the standpoint of higher level logic. */ - slldbg("ERROR failed to allocate timer, nrepls=%d\n", - sporadic->nrepls); + slldbg("Failed to allocate timer, nrepls=%d\n", sporadic->nrepls); } return OK; @@ -866,7 +884,8 @@ uint32_t sched_sporadic_process(FAR struct tcb_s *tcb, uint32_t ticks, */ sporadic_timer_cancel(tcb); - tcb->timeslice = -1; + tcb->timeslice = -1; + sporadic->current = 0; return 0; } @@ -883,19 +902,21 @@ uint32_t sched_sporadic_process(FAR struct tcb_s *tcb, uint32_t ticks, if (noswitches) { - tcb->timeslice = -1; + tcb->timeslice = 1; + sporadic->current = 0; return 1; } /* Another possibility is the the budget interval is equal to the - * entire replenishment interval. This would seem like such a good - * thing to do, but is certainly permitted. + * entire replenishment interval. This would not seem like such a + * good thing to do, but is certainly permitted. */ sporadic = tcb->sporadic; if (sporadic->budget >= sporadic->repl_period) { - tcb->timeslice = sporadic->budget; + tcb->timeslice = sporadic->budget; + sporadic->current = sporadic->budget; return sporadic->budget; } @@ -948,9 +969,12 @@ void sched_sporadic_lowpriority(FAR struct tcb_s *tcb) DEBUGASSERT(tcb && tcb->sporadic); sporadic = tcb->sporadic; - /* Enter the low-priority phase of the replenishment cycle. */ + /* Enter the low-priority phase of the replenishment cycle. (This is + * redundant). + */ - tcb->timeslice = 0; + tcb->timeslice = 0; + sporadic->current = 0; /* Allocate a new replenishment timer. There should be no timers * active at this phase since they were stopped in sched_sporadic_process().