Sporadic scheduler: misc bug fixes
This commit is contained in:
parent
cc1c7731da
commit
8c754ccd4f
@ -272,6 +272,7 @@ 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 last; /* Last budget time */
|
||||
uint32_t pending; /* Unrealized, pending execution budget */
|
||||
|
||||
#ifdef CONFIG_SCHED_TICKLESS
|
||||
@ -808,8 +809,7 @@ void sched_resume_scheduler(FAR struct tcb_s *tcb);
|
||||
*
|
||||
********************************************************************************/
|
||||
|
||||
#if defined(CONFIG_SCHED_SPORADIC) && (defined(CONFIG_SCHED_TICKLESS) || \
|
||||
defined(CONFIG_SPORADIC_INSTRUMENTATION))
|
||||
#ifdef CONFIG_SCHED_SPORADIC
|
||||
void sched_suspend_scheduler(FAR struct tcb_s *tcb);
|
||||
#else
|
||||
# define sched_suspend_scheduler(tcb)
|
||||
|
@ -59,12 +59,7 @@ CSRCS += sched_roundrobin.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SCHED_SPORADIC),y)
|
||||
CSRCS += sched_sporadic.c
|
||||
ifeq ($(CONFIG_SCHED_TICKLESS),y)
|
||||
CSRCS += sched_suspendscheduler.c
|
||||
else ifeq ($(CONFIG_SPORADIC_INSTRUMENTATION),y)
|
||||
CSRCS += sched_suspendscheduler.c
|
||||
endif
|
||||
CSRCS += sched_sporadic.c sched_suspendscheduler.c
|
||||
endif
|
||||
|
||||
ifneq ($(CONFIG_RR_INTERVAL),0)
|
||||
|
187
sched/sched/sched_sporadic.c
Normal file → Executable file
187
sched/sched/sched_sporadic.c
Normal file → Executable file
@ -69,9 +69,11 @@
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static int sporadic_set_hipriority(FAR struct tcb_s *tcb);
|
||||
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_set_lowpriority(FAR struct tcb_s *tcb);
|
||||
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, ...);
|
||||
@ -83,32 +85,25 @@ FAR struct replenishment_s *
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sporadic_budget_start
|
||||
* Name: sporadic_set_hipriority
|
||||
*
|
||||
* Description:
|
||||
* 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.
|
||||
* Force the thread to higher priority.
|
||||
*
|
||||
* Input Parameters:
|
||||
* tcb - TCB of the thread whose priority is being boosted.
|
||||
* repl - The replenishment timer to use
|
||||
* budget - Budgeted execution time
|
||||
* tcb - TCB of task whose priority will be modified
|
||||
*
|
||||
* Returned Value:
|
||||
* Returns zero (OK) on success or a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int sporadic_budget_start(FAR struct tcb_s *tcb,
|
||||
FAR struct replenishment_s *repl,
|
||||
uint32_t budget)
|
||||
static int sporadic_set_hipriority(FAR struct tcb_s *tcb)
|
||||
{
|
||||
FAR struct sporadic_s *sporadic;
|
||||
int ret;
|
||||
|
||||
DEBUGASSERT(tcb && tcb->sporadic);
|
||||
DEBUGASSERT(tcb != NULL && tcb->sporadic != NULL);
|
||||
sporadic = tcb->sporadic;
|
||||
|
||||
#ifdef CONFIG_SPORADIC_INSTRUMENTATION
|
||||
@ -117,22 +112,6 @@ static int sporadic_budget_start(FAR struct tcb_s *tcb,
|
||||
arch_sporadic_start(tcb);
|
||||
#endif
|
||||
|
||||
/* Start the next replenishment interval */
|
||||
|
||||
tcb->timeslice = budget;
|
||||
repl->budget = budget;
|
||||
|
||||
#ifdef CONFIG_SCHED_TICKLESS
|
||||
/* Save the time that the replenishment interval started */
|
||||
|
||||
(void)up_timer_gettime(&sporadic->sched_time);
|
||||
#endif
|
||||
|
||||
/* And start the timer for the budget interval */
|
||||
|
||||
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
|
||||
* reset the base priority.
|
||||
@ -173,6 +152,57 @@ static int sporadic_budget_start(FAR struct tcb_s *tcb,
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sporadic_budget_start
|
||||
*
|
||||
* Description:
|
||||
* 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.
|
||||
*
|
||||
* 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 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 = budget;
|
||||
sporadic->last = budget;
|
||||
repl->budget = budget;
|
||||
|
||||
#ifdef CONFIG_SCHED_TICKLESS
|
||||
/* Save the time that the replenishment interval started */
|
||||
|
||||
(void)up_timer_gettime(&sporadic->sched_time);
|
||||
#endif
|
||||
|
||||
/* And start the timer for the budget interval */
|
||||
|
||||
DEBUGVERIFY(wd_start(&repl->timer, budget, sporadic_budget_expire, 1,
|
||||
(wdentry_t)repl));
|
||||
|
||||
/* Then reprioritize to the higher priority */
|
||||
|
||||
return sporadic_set_hipriority(tcb);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sporadic_budget_next
|
||||
*
|
||||
@ -201,15 +231,8 @@ static int sporadic_budget_next(FAR struct replenishment_s *repl)
|
||||
|
||||
/* 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;
|
||||
budget = sporadic->pending;
|
||||
sporadic->pending = 0;
|
||||
|
||||
/* If the budget zero, then all of the pending budget has been utilized.
|
||||
* There are now two possibilities: (1) There are multiple, active
|
||||
@ -228,6 +251,8 @@ static int sporadic_budget_next(FAR struct replenishment_s *repl)
|
||||
|
||||
repl->active = false;
|
||||
sporadic->nrepls--;
|
||||
|
||||
return sporadic_set_hipriority(tcb);
|
||||
return OK;
|
||||
}
|
||||
else
|
||||
@ -252,7 +277,7 @@ static int sporadic_budget_next(FAR struct replenishment_s *repl)
|
||||
* Force the thread to lower priority.
|
||||
*
|
||||
* Input Parameters:
|
||||
* repl - Replenishment timer to be used
|
||||
* tcb - TCB of task whose priority will be modified
|
||||
*
|
||||
* Returned Value:
|
||||
* Returns zero (OK) on success or a negated errno value on failure.
|
||||
@ -333,7 +358,7 @@ static int sporadic_interval_start(FAR struct replenishment_s *repl)
|
||||
|
||||
/* Enter the low-priority phase of the replenishment cycle */
|
||||
|
||||
tcb->timeslice = 0;
|
||||
tcb->timeslice = 0;
|
||||
|
||||
/* Calculate the remainder of the replenishment interval. This is
|
||||
* permitted to be zero, in which case we just restart the budget
|
||||
@ -385,7 +410,6 @@ static void sporadic_budget_expire(int argc, wdparm_t 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 && repl != NULL && repl->tcb != NULL);
|
||||
tcb = repl->tcb;
|
||||
@ -407,34 +431,19 @@ static void sporadic_budget_expire(int argc, wdparm_t arg1, ...)
|
||||
{
|
||||
DEBUGASSERT(repl->active && sporadic->nrepls > 0);
|
||||
|
||||
/* Set the timeslice to the magic value */
|
||||
|
||||
tcb->timeslice = -1;
|
||||
|
||||
/* Cancel and free the timer */
|
||||
|
||||
wd_cancel(&repl->timer);
|
||||
repl->budget = 0;
|
||||
repl->active = false;
|
||||
sporadic->nrepls--;
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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(repl->budget >= tcb->timeslice);
|
||||
pending = sporadic->pending + repl->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.
|
||||
*/
|
||||
@ -658,6 +667,7 @@ int sched_sporadic_start(FAR struct tcb_s *tcb)
|
||||
|
||||
/* Then start the first interval */
|
||||
|
||||
sporadic->pending = sporadic->budget;
|
||||
return sporadic_budget_start(tcb, repl, sporadic->budget);
|
||||
}
|
||||
|
||||
@ -814,7 +824,7 @@ int sched_sporadic_resume(FAR struct tcb_s *tcb)
|
||||
* not want to start a new timer in these cases.
|
||||
*/
|
||||
|
||||
if (tcb->timeslice > 0 && tcb->timeslice < sporadic->budget)
|
||||
if (tcb->timeslice > 0 && tcb->timeslice < sporadic->last)
|
||||
{
|
||||
/* Allocate a new replenishment timer. This will limit us to
|
||||
* to maximum number of replenishments (max_repl).
|
||||
@ -868,19 +878,18 @@ int sched_sporadic_resume(FAR struct tcb_s *tcb)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#if defined(CONFIG_SCHED_SPORADIC) && (defined(CONFIG_SCHED_TICKLESS) || \
|
||||
defined(CONFIG_SPORADIC_INSTRUMENTATION))
|
||||
int sched_sporadic_suspend(FAR struct tcb_s *tcb,
|
||||
FAR const struct timespec *suspend_time)
|
||||
{
|
||||
#ifdef CONFIG_SCHED_TICKLESS
|
||||
FAR struct sporadic_s *sporadic;
|
||||
#ifdef CONFIG_SCHED_TICKLESS
|
||||
struct timespec elapsed_time;
|
||||
uint32_t elapsed_ticks;
|
||||
#endif
|
||||
uint32_t pending = tcb->timeslice;
|
||||
|
||||
DEBUGASSERT(tcb && tcb->sporadic);
|
||||
sporadic = tcb->sporadic;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SPORADIC_INSTRUMENTATION
|
||||
/* Inform the monitor of this event */
|
||||
@ -888,7 +897,6 @@ int sched_sporadic_suspend(FAR struct tcb_s *tcb,
|
||||
arch_sporadic_suspend(tcb);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SCHED_TICKLESS
|
||||
/* Check if are in the budget portion of the replenishment interval. We
|
||||
* know this is the case if the current timeslice is non-zero.
|
||||
*
|
||||
@ -902,10 +910,11 @@ int sched_sporadic_suspend(FAR struct tcb_s *tcb,
|
||||
* not want to start a new timer in these cases.
|
||||
*/
|
||||
|
||||
if (tcb->timeslice > 0 && tcb->timeslice < sporadic->budget)
|
||||
if (tcb->timeslice > 0)
|
||||
{
|
||||
#ifdef CONFIG_SCHED_TICKLESS
|
||||
/* Get the difference in time between the time that the scheduler just
|
||||
* ran and time time that the thread was spuspended. This difference,
|
||||
* ran and time time that the thread was suspended. This difference,
|
||||
* then, is the unaccounted for time between the time that the timer
|
||||
* was started and when the thread was suspended.
|
||||
*/
|
||||
@ -920,32 +929,37 @@ int sched_sporadic_suspend(FAR struct tcb_s *tcb,
|
||||
|
||||
/* One possibility is that the the elapsed time is greater than the
|
||||
* time remaining in the time slice. This is a a race condition. It
|
||||
* means that the timer has just expired.
|
||||
*
|
||||
* Ideally, we would need to cancel the budget time and start the low-
|
||||
* priority portion of the interval. But we are in a precarious
|
||||
* situation here.. The TCB has been removed from the ready to run
|
||||
* list already so we cannot use the normal reprioritization logic.
|
||||
* means that the timer has just expired. the interrupt will occu
|
||||
* soon.
|
||||
*/
|
||||
|
||||
if (elapsed_ticks >= tcb->timeslice)
|
||||
{
|
||||
/* REVISIT: The kludge here is to just set the clock to one tick.
|
||||
* That will cause the interval to expire very quickly.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
tcb->timeslice = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
tcb->timeslice -= (int32_t)elapsed_ticks;
|
||||
}
|
||||
}
|
||||
/* Otherwise, the pending time in this budget is the sum time slice
|
||||
* value minus, the time from the unexpired timer.
|
||||
*/
|
||||
|
||||
tcb->timeslice -= (int32_t)elapsed_ticks;
|
||||
#endif
|
||||
|
||||
/* Handle any part of the budget that was not utilized.
|
||||
*
|
||||
* current = The initial budget at the beginning of the interval.
|
||||
* tcb->timeslice = The unused part of that budget when the thread did
|
||||
* not execute.
|
||||
*/
|
||||
|
||||
DEBUGASSERT(sporadic->last >= tcb->timeslice);
|
||||
pending = sporadic->last - tcb->timeslice;
|
||||
DEBUGASSERT(pending <= sporadic->budget);
|
||||
}
|
||||
|
||||
sporadic->pending = pending;
|
||||
return OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sched_sporadic_process
|
||||
@ -1116,6 +1130,7 @@ void sched_sporadic_lowpriority(FAR struct tcb_s *tcb)
|
||||
DEBUGASSERT(sporadic->nrepls < sporadic->max_repl);
|
||||
repl = sporadic_alloc_repl(sporadic);
|
||||
DEBUGASSERT(repl != NULL);
|
||||
repl->budget = sporadic->budget;
|
||||
|
||||
/* Drop the priority of thread, possible causing a context switch. */
|
||||
|
||||
|
@ -49,8 +49,7 @@
|
||||
#include "clock/clock.h"
|
||||
#include "sched/sched.h"
|
||||
|
||||
#if defined(CONFIG_SCHED_SPORADIC) && (defined(CONFIG_SCHED_TICKLESS) || \
|
||||
defined(CONFIG_SPORADIC_INSTRUMENTATION))
|
||||
#ifdef CONFIG_SCHED_SPORADIC
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
@ -91,4 +90,4 @@ void sched_suspend_scheduler(FAR struct tcb_s *tcb)
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SCHED_SPORADIC && (CONFIG_SCHED_TICKLESS || CONFIG_SPORADIC_INSTRUMENTATION) */
|
||||
#endif /* CONFIG_SCHED_SPORADIC */
|
||||
|
Loading…
Reference in New Issue
Block a user