Fixes several more sporadic scheduler bugs

This commit is contained in:
Gregory Nutt 2015-07-27 18:08:21 -06:00
parent a7322f5a6d
commit 95ca3a1d1e
2 changed files with 61 additions and 49 deletions

View File

@ -267,6 +267,7 @@ struct replenishment_s
struct sporadic_s struct sporadic_s
{ {
bool suspended; /* Thread is currently suspended */
uint8_t hi_priority; /* Sporadic high priority */ uint8_t hi_priority; /* Sporadic high priority */
uint8_t low_priority; /* Sporadic low priority */ uint8_t low_priority; /* Sporadic low priority */
uint8_t max_repl; /* Maximum number of replenishments */ uint8_t max_repl; /* Maximum number of replenishments */

View File

@ -77,6 +77,7 @@ static int sporadic_set_lowpriority(FAR struct tcb_s *tcb);
static int sporadic_interval_start(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_budget_expire(int argc, wdparm_t arg1, ...);
static void sporadic_interval_expire(int argc, wdparm_t arg1, ...); static void sporadic_interval_expire(int argc, wdparm_t arg1, ...);
static void sporadic_timer_cancel(FAR struct tcb_s *tcb);
FAR struct replenishment_s * FAR struct replenishment_s *
sporadic_alloc_repl(FAR struct sporadic_s *sporadic); sporadic_alloc_repl(FAR struct sporadic_s *sporadic);
@ -187,21 +188,11 @@ static int sporadic_budget_start(FAR struct tcb_s *tcb,
repl->budget = budget; repl->budget = budget;
repl->unrealized = 0; repl->unrealized = 0;
#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 */ /* And start the timer for the budget interval */
DEBUGVERIFY(wd_start(&repl->timer, budget, sporadic_budget_expire, 1, DEBUGVERIFY(wd_start(&repl->timer, budget, sporadic_budget_expire, 1,
(wdentry_t)repl)); (wdentry_t)repl));
/* Save the time that the thread was started */
sporadic->eventtime = clock_systimer();
/* Then reprioritize to the higher priority */ /* Then reprioritize to the higher priority */
return sporadic_set_hipriority(tcb); return sporadic_set_hipriority(tcb);
@ -439,12 +430,9 @@ static void sporadic_budget_expire(int argc, wdparm_t arg1, ...)
tcb->timeslice = -1; tcb->timeslice = -1;
/* Cancel and free the timer */ /* Cancel and free all timers */
wd_cancel(&repl->timer); sporadic_timer_cancel(tcb);
repl->budget = 0;
repl->active = false;
sporadic->nrepls--;
return; return;
} }
@ -664,6 +652,11 @@ int sched_sporadic_start(FAR struct tcb_s *tcb)
repl = sporadic_alloc_repl(sporadic); repl = sporadic_alloc_repl(sporadic);
DEBUGASSERT(repl != NULL && sporadic->nrepls == 1); DEBUGASSERT(repl != NULL && sporadic->nrepls == 1);
/* Save the time that the scheduler was started */
sporadic->eventtime = clock_systimer();
sporadic->suspended = true;
/* Then start the first interval */ /* Then start the first interval */
return sporadic_budget_start(tcb, repl, sporadic->budget); return sporadic_budget_start(tcb, repl, sporadic->budget);
@ -762,6 +755,7 @@ int sched_sporadic_reset(FAR struct tcb_s *tcb)
/* Reset sporadic scheduling parameters and state data */ /* Reset sporadic scheduling parameters and state data */
sporadic->suspended = true;
sporadic->hi_priority = 0; sporadic->hi_priority = 0;
sporadic->low_priority = 0; sporadic->low_priority = 0;
sporadic->max_repl = 0; sporadic->max_repl = 0;
@ -784,7 +778,7 @@ int sched_sporadic_reset(FAR struct tcb_s *tcb)
* using the sporadic scheduling policy. * using the sporadic scheduling policy.
* *
* This function does nothing if the budget phase as already elapsed or * This function does nothing if the budget phase as already elapsed or
* the maximum numer of replenishments have already been performed. * the maximum number of replenishments have already been performed.
* *
* Input Parameters: * Input Parameters:
* tcb - The TCB of the thread that is beginning sporadic scheduling. * tcb - The TCB of the thread that is beginning sporadic scheduling.
@ -810,26 +804,36 @@ int sched_sporadic_resume(FAR struct tcb_s *tcb)
DEBUGASSERT(tcb && tcb->sporadic); DEBUGASSERT(tcb && tcb->sporadic);
sporadic = tcb->sporadic; sporadic = tcb->sporadic;
/* If we are resumed more than one, ignore all but the first */
if (!sporadic->suspended)
{
return OK;
}
/* This is the first time */
sporadic->suspended = false;
#ifdef CONFIG_SPORADIC_INSTRUMENTATION #ifdef CONFIG_SPORADIC_INSTRUMENTATION
/* Inform the monitor of this event */ /* Inform the monitor of this event */
arch_sporadic_resume(tcb); arch_sporadic_resume(tcb);
#endif #endif
/* Get the time that the thread was [re-]started */
now = clock_systimer();
/* Check if are in the budget portion of the replenishment interval. We /* Check if are in the budget portion of the replenishment interval. We
* know this is the case if the current timeslice is non-zero. * know this is the case if the current timeslice is non-zero.
*/ */
if (tcb->timeslice > 0) if (tcb->timeslice > 0)
{ {
/* Save the time that the thread was [re-]started */
now = clock_systimer();
/* Unrealized budget time while the thread was suspended */ /* Unrealized budget time while the thread was suspended */
unrealized = sporadic->eventtime - now; unrealized = now - sporadic->eventtime;
sporadic->eventtime = now;
/* Ignore very short pre-emptions that are below our timing resolution. */ /* Ignore very short pre-emptions that are below our timing resolution. */
@ -837,10 +841,10 @@ int sched_sporadic_resume(FAR struct tcb_s *tcb)
{ {
/* Handle any part of the budget that was not utilized. /* Handle any part of the budget that was not utilized.
* *
* current = The initial budget at the beginning of the * current = The initial budget at the beginning of the
* interval. * interval.
* urealized = The unused part of that budget when the * unrealized = The unused part of that budget when the
* thread did not execute. * thread did not execute.
*/ */
if (unrealized >= tcb->timeslice) if (unrealized >= tcb->timeslice)
@ -848,11 +852,10 @@ int sched_sporadic_resume(FAR struct tcb_s *tcb)
/* We lost the remainder of the timeslice, (and then some). /* We lost the remainder of the timeslice, (and then some).
* No point in starting more timers. * No point in starting more timers.
*/ */
return OK; return OK;
} }
DEBUGASSERT(sporadic->active); DEBUGASSERT(sporadic->active);
tcb->timeslice -= unrealized; tcb->timeslice -= unrealized;
sporadic->active->unrealized = unrealized; sporadic->active->unrealized = unrealized;
@ -888,6 +891,7 @@ int sched_sporadic_resume(FAR struct tcb_s *tcb)
} }
} }
sporadic->eventtime = now;
return OK; return OK;
} }
@ -895,25 +899,17 @@ int sched_sporadic_resume(FAR struct tcb_s *tcb)
* Name: sched_sporadic_suspend * Name: sched_sporadic_suspend
* *
* Description: * Description:
* Called to when a thread with sporadic scheduling is suspended in the * Called to when a thread with sporadic scheduling is suspended. In this
* tickless mode. In this case, there is unaccounted for time from the * case, there will be unaccounted for time from the time that the last
* time that the last interval timer was started up until this point. * when the task is resumed. All that we need to do here is remember
* * that time that we were suspended.
* This function calculates the elapsed time since then, and adjusts the
* timeslice time accordingly.
* *
* Input Parameters: * Input Parameters:
* tcb - The TCB of the thread that is beginning sporadic scheduling. * tcb - The TCB of the thread that is beginning sporadic scheduling.
* suspend_time - The time that the thread was suspended.
* *
* Returned Value: * Returned Value:
* Returns zero (OK) on success or a negated errno value on failure. * 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 low priority interval timer is not running
*
****************************************************************************/ ****************************************************************************/
int sched_sporadic_suspend(FAR struct tcb_s *tcb) int sched_sporadic_suspend(FAR struct tcb_s *tcb)
@ -923,15 +919,25 @@ int sched_sporadic_suspend(FAR struct tcb_s *tcb)
DEBUGASSERT(tcb && tcb->sporadic); DEBUGASSERT(tcb && tcb->sporadic);
sporadic = tcb->sporadic; sporadic = tcb->sporadic;
#ifdef CONFIG_SPORADIC_INSTRUMENTATION /* If we are suspended more than one, ignore all but the first */
/* Inform the monitor of this event */
arch_sporadic_suspend(tcb); if (!sporadic->suspended)
{
/* This is the first time */
sporadic->suspended = true;
#ifdef CONFIG_SPORADIC_INSTRUMENTATION
/* Inform the monitor of this event */
arch_sporadic_suspend(tcb);
#endif #endif
/* Save the time that the thread was suspended */ /* Save the time that the thread was suspended */
sporadic->eventtime = clock_systimer();
}
sporadic->eventtime = clock_systimer();
return OK; return OK;
} }
@ -1028,7 +1034,7 @@ uint32_t sched_sporadic_process(FAR struct tcb_s *tcb, uint32_t ticks,
if (noswitches) if (noswitches)
{ {
tcb->timeslice = 1; tcb->timeslice = 1;
return 1; return 1;
} }
@ -1043,9 +1049,10 @@ uint32_t sched_sporadic_process(FAR struct tcb_s *tcb, uint32_t ticks,
return sporadic->budget; return sporadic->budget;
} }
/* Otherwise enter the low-priority phase of the replenishment cycle */ /* Otherwise enter the low-priority phase of the replenishment cycle.
* Let the timers handle the priority changes.
*/
sporadic_set_lowpriority(tcb);
return 0; return 0;
} }
@ -1104,7 +1111,11 @@ void sched_sporadic_lowpriority(FAR struct tcb_s *tcb)
DEBUGASSERT(sporadic->nrepls < sporadic->max_repl); DEBUGASSERT(sporadic->nrepls < sporadic->max_repl);
repl = sporadic_alloc_repl(sporadic); repl = sporadic_alloc_repl(sporadic);
DEBUGASSERT(repl != NULL); DEBUGASSERT(repl != NULL);
repl->budget = sporadic->budget;
tcb->timeslice = 0;
sporadic->active = repl;
repl->budget = sporadic->budget;
repl->unrealized = 0;
/* Drop the priority of thread, possible causing a context switch. */ /* Drop the priority of thread, possible causing a context switch. */