mcs: update refills based on spec

This is a list of fixes that came up while working on the verification
spec for the mcs changes.

- trigger a timer tick if we are unable to split a refill
due to the refill list being full.
- make refill_ordered more useful
- pull the thread out of the scheduler before updating it
- simplify refill logic at verifications request
- Add unused to refill_sum
- Don't refill_split_check if consumed is empty
- sched_control: fix double increment bug
- sched-control: charge before reconfiguring ksCurSC
- Charge round robin threads differently

Sporadic server refill rules do not behave correctly for round robin
threads, instead, change the logic. Round robin threads have 2 refills:
current and next.
This commit is contained in:
Anna Lyons 2017-04-27 15:40:12 +10:00 committed by Kent Mcleod
parent 798fb76ded
commit 9253704d2c
8 changed files with 248 additions and 176 deletions

View file

@ -53,6 +53,11 @@ static inline word_t refill_size(sched_context_t *sc)
return sc->scRefillTail + 1u + (sc->scRefillMax - sc->scRefillHead);
}
static inline bool_t refill_full(sched_context_t *sc)
{
return refill_size(sc) == sc->scRefillMax;
}
static inline bool_t refill_single(sched_context_t *sc)
{
return sc->scRefillHead == sc->scRefillTail;
@ -101,9 +106,8 @@ void refill_update(sched_context_t *sc, ticks_t new_period, ticks_t new_budget,
* `used` amount from its current replenishment without
* depleting the budget, i.e refill_expired returns false.
*
* return any uncharged usage.
*/
ticks_t refill_budget_check(sched_context_t *sc, ticks_t used);
void refill_budget_check(sched_context_t *sc, ticks_t used, ticks_t capacity);
/*
* Charge a scheduling context `used` amount from its

View file

@ -86,28 +86,42 @@ static inline bool_t isHighestPrio(word_t dom, prio_t prio)
}
#ifdef CONFIG_KERNEL_MCS
static inline bool_t PURE isRoundRobin(sched_context_t *sc)
{
return sc->scPeriod == 0;
}
static inline bool_t isCurDomainExpired(void)
{
return CONFIG_NUM_DOMAINS > 1 &&
ksDomainTime < (NODE_STATE(ksConsumed) + getKernelWcetTicks());
ksDomainTime < (NODE_STATE(ksConsumed) + MIN_BUDGET);
}
static inline void commitTime(void)
{
if (likely(NODE_STATE(ksConsumed) > 0 && (NODE_STATE(ksCurThread) != NODE_STATE(ksIdleThread)))) {
if (likely(NODE_STATE(ksConsumed) > 0)) {
/* if this function is called the head refil must be sufficient to
* charge ksConsumed */
assert(refill_sufficient(NODE_STATE(ksCurSC), NODE_STATE(ksConsumed)));
/* and it must be ready to use */
assert(refill_ready(NODE_STATE(ksCurSC)));
refill_split_check(NODE_STATE(ksCurSC), NODE_STATE(ksConsumed));
if (isRoundRobin(NODE_STATE(ksCurSC))) {
/* for round robin threads, there are only two refills: the HEAD, which is what
* we are consuming, and the tail, which is what we have consumed */
assert(refill_size(NODE_STATE(ksCurSC)) == MIN_REFILLS);
REFILL_HEAD(NODE_STATE(ksCurSC)).rAmount -= NODE_STATE(ksConsumed);
REFILL_TAIL(NODE_STATE(ksCurSC)).rAmount += NODE_STATE(ksConsumed);
} else {
refill_split_check(NODE_STATE(ksCurSC), NODE_STATE(ksConsumed));
}
assert(refill_sufficient(NODE_STATE(ksCurSC), 0));
assert(refill_ready(NODE_STATE(ksCurSC)));
}
if (CONFIG_NUM_DOMAINS > 1) {
if (unlikely(ksDomainTime < NODE_STATE(ksConsumed))) {
ksDomainTime = 0;
} else {
ksDomainTime -= NODE_STATE(ksConsumed);
}
assert(ksDomainTime > NODE_STATE(ksConsumed));
assert(ksDomainTime - NODE_STATE(ksConsumed) >= MIN_BUDGET);
ksDomainTime -= NODE_STATE(ksConsumed);
}
NODE_STATE(ksConsumed) = 0llu;
@ -171,6 +185,9 @@ static inline void updateRestartPC(tcb_t *tcb)
*/
void endTimeslice(void);
/* called when a thread has used up its head refill */
void chargeBudget(ticks_t capacity, ticks_t consumed);
/* Update the kernels timestamp and stores in ksCurTime.
* The difference between the previous kernel timestamp and the one just read
* is stored in ksConsumed.
@ -199,31 +216,23 @@ static inline bool_t checkBudget(void)
/* currently running thread must have available capacity */
assert(refill_ready(NODE_STATE(ksCurSC)));
if (unlikely(NODE_STATE(ksCurThread) == NODE_STATE(ksIdleThread))) {
ticks_t capacity = refill_capacity(NODE_STATE(ksCurSC), NODE_STATE(ksConsumed));
/* if the budget isn't enough, the timeslice for this SC is over. For
* round robin threads this is sufficient, however for periodic threads
* we also need to check there is space to schedule the replenishment - if the refill
* is full then the timeslice is also over as the rest of the budget is forfeit. */
if (likely(capacity >= MIN_BUDGET && (isRoundRobin(NODE_STATE(ksCurSC)) ||
!refill_full(NODE_STATE(ksCurSC))))) {
if (unlikely(isCurDomainExpired())) {
commitTime();
rescheduleRequired();
return false;
}
return true;
}
ticks_t capacity = refill_capacity(NODE_STATE(ksCurSC), NODE_STATE(ksConsumed));
if (unlikely(capacity < MIN_BUDGET)) {
if (capacity == 0) {
NODE_STATE(ksConsumed) = refill_budget_check(NODE_STATE(ksCurSC), NODE_STATE(ksConsumed));
}
if (NODE_STATE(ksConsumed) > 0) {
refill_split_check(NODE_STATE(ksCurSC), NODE_STATE(ksConsumed));
}
NODE_STATE(ksConsumed) = 0;
NODE_STATE(ksCurTime) += 1llu;
if (likely(isRunnable(NODE_STATE(ksCurThread)))) {
endTimeslice();
rescheduleRequired();
}
return false;
} else if (unlikely(isCurDomainExpired())) {
commitTime();
rescheduleRequired();
return false;
}
return true;
chargeBudget(capacity, NODE_STATE(ksConsumed));
return false;
}
/* Everything checkBudget does, but also set the thread

View file

@ -42,7 +42,6 @@ exception_t handleInterruptEntry(void)
irq = getActiveIRQ();
#ifdef CONFIG_KERNEL_MCS
if (SMP_TERNARY(clh_is_self_in_queue(), 1)) {
assert(irq != irq_remote_call_ipi);
updateTimestamp();
checkBudget();
}
@ -60,7 +59,6 @@ exception_t handleInterruptEntry(void)
#ifdef CONFIG_KERNEL_MCS
if (SMP_TERNARY(clh_is_self_in_queue(), 1)) {
assert(irq != irq_remote_call_ipi);
#endif
schedule();
activateThread();
@ -534,14 +532,8 @@ static inline void mcsIRQ(irq_t irq)
static void handleYield(void)
{
#ifdef CONFIG_KERNEL_MCS
/* checkBudgetRestart should have failed if we got here */
assert(refill_sufficient(NODE_STATE(ksCurSC), NODE_STATE(ksConsumed)));
/* Yield the current remaining budget */
refill_budget_check(NODE_STATE(ksCurSC), REFILL_HEAD(NODE_STATE(ksCurSC)).rAmount);
/* we just charged all of the time to the yielding thread */
NODE_STATE(ksConsumed) = 0;
endTimeslice();
rescheduleRequired();
chargeBudget(0, REFILL_HEAD(NODE_STATE(ksCurSC)).rAmount);
#else
tcbSchedDequeue(NODE_STATE(ksCurThread));
SCHED_APPEND_CURRENT_TCB;

View file

@ -73,16 +73,21 @@ static UNUSED bool_t refill_ordered(sched_context_t *sc)
word_t next = refill_next(sc, sc->scRefillHead);
while (current != sc->scRefillTail) {
assert(REFILL_INDEX(sc, current).rTime <= REFILL_INDEX(sc, next).rTime);
if (!(REFILL_INDEX(sc, current).rTime <= REFILL_INDEX(sc, next).rTime)) {
refill_print(sc);
return false;
}
current = next;
next = refill_next(sc, current);
}
return true;
}
#define REFILL_SANITY_START(sc) ticks_t _sum = refill_sum(sc); refill_ordered(sc);
#define REFILL_SANITY_START(sc) ticks_t _sum = refill_sum(sc); assert(refill_ordered(sc));
#define REFILL_SANITY_CHECK(sc, budget) \
do { \
assert(refill_sum(sc) == budget); refill_ordered(sc); \
assert(refill_sum(sc) == budget); assert(refill_ordered(sc)); \
} while (0)
#define REFILL_SANITY_END(sc) \
@ -96,7 +101,7 @@ static UNUSED bool_t refill_ordered(sched_context_t *sc)
#endif /* CONFIG_DEBUG_BUILD */
/* compute the sum of a refill queue */
static ticks_t refill_sum(sched_context_t *sc)
static UNUSED ticks_t refill_sum(sched_context_t *sc)
{
ticks_t sum = REFILL_HEAD(sc).rAmount;
word_t current = sc->scRefillHead;
@ -128,8 +133,6 @@ static inline refill_t refill_pop_head(sched_context_t *sc)
/* add item to tail of refill queue */
static inline void refill_add_tail(sched_context_t *sc, refill_t refill)
{
/* cannot add an empty refill */
assert(refill.rAmount != 0);
/* cannot add beyond queue size */
assert(refill_size(sc) < sc->scRefillMax);
@ -141,6 +144,16 @@ static inline void refill_add_tail(sched_context_t *sc, refill_t refill)
assert(new_tail < sc->scRefillMax);
}
static inline void maybe_add_empty_tail(sched_context_t *sc)
{
if (isRoundRobin(sc)) {
/* add an empty refill - we track the used up time here */
refill_t empty_tail = { .rTime = NODE_STATE(ksCurTime)};
refill_add_tail(sc, empty_tail);
assert(refill_size(sc) == MIN_REFILLS);
}
}
void refill_new(sched_context_t *sc, word_t max_refills, ticks_t budget, ticks_t period)
{
sc->scPeriod = period;
@ -152,6 +165,7 @@ void refill_new(sched_context_t *sc, word_t max_refills, ticks_t budget, ticks_t
REFILL_HEAD(sc).rAmount = budget;
/* budget can be used from now */
REFILL_HEAD(sc).rTime = NODE_STATE(ksCurTime);
maybe_add_empty_tail(sc);
REFILL_SANITY_CHECK(sc, budget);
}
@ -161,90 +175,78 @@ void refill_update(sched_context_t *sc, ticks_t new_period, ticks_t new_budget,
/* refill must be initialised in order to be updated - otherwise refill_new should be used */
assert(sc->scRefillMax > 0);
/* figure out how much budget is available */
ticks_t total_budget = refill_sum(sc);
REFILL_SANITY_CHECK(sc, total_budget);
/* this is called on an active thread. We want to preserve the sliding window constraint -
* so over new_period, new_budget should not be exceeded even temporarily */
/* first deal with a difference in max refills - merge
* any refills that exceed the new max */
while (new_max_refills < refill_size(sc)) {
/* merge refills */
assert(!refill_single(sc));
refill_t refill = refill_pop_head(sc);
REFILL_HEAD(sc).rAmount += refill.rAmount;
}
REFILL_SANITY_CHECK(sc, total_budget);
/* move anything in the list that is beyond the old max */
if (sc->scRefillMax > new_max_refills) {
word_t curr = sc->scRefillHead;
for (curr = sc->scRefillHead; curr < sc->scRefillMax; curr++) {
word_t diff = sc->scRefillMax - new_max_refills;
REFILL_INDEX(sc, curr - diff) = REFILL_INDEX(sc, curr);
}
}
/* move the head refill to the start of the list - it's ok as we're going to truncate the
* list to size 1 - and this way we can't be in an invalid list position once new_max_refills
* is updated */
REFILL_INDEX(sc, 0) = REFILL_HEAD(sc);
sc->scRefillHead = 0;
/* truncate refill list to size 1 */
sc->scRefillTail = sc->scRefillHead;
/* update max refills */
sc->scRefillMax = new_max_refills;
/* now deal with the period change - update each refill by the difference in period */
word_t current = refill_next(sc, sc->scRefillHead);
while (current != sc->scRefillTail) {
/* adjust the period of each refill by new one (except the head) */
REFILL_INDEX(sc, current).rTime += (new_period - sc->scPeriod);
current = refill_next(sc, current);
}
/* update period */
sc->scPeriod = new_period;
REFILL_SANITY_CHECK(sc, total_budget);
/* now deal with the new budget */
if (new_budget > total_budget) {
/* if the budget has increased, just add it to the last refill */
REFILL_TAIL(sc).rAmount += (new_budget - total_budget);
} else {
/* if the budget has decreased, iterate through from head to
* tail until the amount decreased has been removed from the refill
* buffer */
ticks_t remove = total_budget - new_budget;
while (remove >= REFILL_HEAD(sc).rAmount) {
assert(!refill_single(sc));
refill_t old_head = refill_pop_head(sc);
remove -= old_head.rAmount;
}
REFILL_HEAD(sc).rAmount -= remove;
if (REFILL_HEAD(sc).rAmount < MIN_BUDGET) {
assert(!refill_single(sc));
refill_t old_head = refill_pop_head(sc);
REFILL_HEAD(sc).rAmount += old_head.rAmount;
}
if (refill_ready(sc)) {
REFILL_HEAD(sc).rTime = NODE_STATE(ksCurTime);
}
if (REFILL_HEAD(sc).rAmount >= new_budget) {
/* if the heads budget exceeds the new budget just trim it */
REFILL_HEAD(sc).rAmount = new_budget;
maybe_add_empty_tail(sc);
} else {
/* otherwise schedule the rest for the next period */
refill_t new = { .rAmount = (new_budget - REFILL_HEAD(sc).rAmount),
.rTime = REFILL_HEAD(sc).rTime + new_period
};
refill_add_tail(sc, new);
}
/* merge any overlapping refills */
refill_unblock_check(sc);
REFILL_SANITY_CHECK(sc, new_budget);
}
ticks_t refill_budget_check(sched_context_t *sc, ticks_t usage)
static inline void schedule_used(sched_context_t *sc, refill_t new)
{
/* schedule the used amount */
if (new.rAmount < MIN_BUDGET && !refill_single(sc)) {
/* used amount is to small - merge with last and delay */
REFILL_TAIL(sc).rAmount += new.rAmount;
REFILL_TAIL(sc).rTime = MAX(new.rTime, REFILL_TAIL(sc).rTime);
} else if (new.rTime <= REFILL_TAIL(sc).rTime) {
REFILL_TAIL(sc).rAmount += new.rAmount;
} else {
refill_add_tail(sc, new);
}
}
void refill_budget_check(sched_context_t *sc, ticks_t usage, ticks_t capacity)
{
/* this function should only be called when the sc is out of budget */
assert(refill_capacity(sc, usage) == 0);
assert(capacity < MIN_BUDGET || refill_full(sc));
assert(sc->scPeriod > 0);
REFILL_SANITY_START(sc);
while (REFILL_HEAD(sc).rAmount <= usage) {
/* exhaust and schedule replenishment */
usage -= REFILL_HEAD(sc).rAmount;
if (refill_single(sc)) {
/* update in place */
REFILL_HEAD(sc).rTime += sc->scPeriod;
} else {
refill_t old_head = refill_pop_head(sc);
old_head.rTime = old_head.rTime + sc->scPeriod;
refill_add_tail(sc, old_head);
if (capacity == 0) {
while (REFILL_HEAD(sc).rAmount <= usage) {
/* exhaust and schedule replenishment */
usage -= REFILL_HEAD(sc).rAmount;
if (refill_single(sc)) {
/* update in place */
REFILL_HEAD(sc).rTime += sc->scPeriod;
} else {
refill_t old_head = refill_pop_head(sc);
old_head.rTime = old_head.rTime + sc->scPeriod;
schedule_used(sc, old_head);
}
}
}
/* budget overrun */
if (usage > 0 && sc->scPeriod > 0) {
if (usage > 0) {
/* budget reduced when calculating capacity */
/* due to overrun delay next replenishment */
REFILL_HEAD(sc).rTime += usage;
@ -255,13 +257,25 @@ ticks_t refill_budget_check(sched_context_t *sc, ticks_t usage)
refill_t refill = refill_pop_head(sc);
REFILL_HEAD(sc).rAmount += refill.rAmount;
REFILL_HEAD(sc).rTime = refill.rTime;
}
}
REFILL_SANITY_END(sc);
capacity = refill_capacity(sc, usage);
if (capacity > 0 && refill_ready(sc)) {
refill_split_check(sc, usage);
}
/* return any usage we haven't dealt with */
return usage;
/* ensure the refill head is sufficient, such that when we wake in awaken,
* there is enough budget to run */
while (REFILL_HEAD(NODE_STATE(ksCurSC)).rAmount < MIN_BUDGET) {
refill_t refill = refill_pop_head(sc);
REFILL_HEAD(sc).rAmount += refill.rAmount;
/* this loop is guaranteed to terminate as the sum of
* rAmount in a refill must be >= MIN_BUDGET */
}
REFILL_SANITY_END(sc);
}
void refill_split_check(sched_context_t *sc, ticks_t usage)
@ -272,40 +286,50 @@ void refill_split_check(sched_context_t *sc, ticks_t usage)
* time has been used */
assert(usage > 0);
assert(usage <= REFILL_HEAD(sc).rAmount);
assert(sc->scPeriod > 0);
REFILL_SANITY_START(sc);
/* first deal with the remaining budget of the current replenishment */
ticks_t remnant = REFILL_HEAD(sc).rAmount - usage;
if (remnant < MIN_BUDGET && refill_single(sc)) {
/* delay entire replenishment - can't merge, nothing to merge with */
REFILL_HEAD(sc).rTime += sc->scPeriod;
REFILL_SANITY_END(sc);
return;
}
if (refill_size(sc) == sc->scRefillMax || remnant < MIN_BUDGET) {
assert(!refill_single(sc));
/* merge remnant with next replenishment - either it's too small
* or we're out of space */
refill_pop_head(sc);
REFILL_HEAD(sc).rAmount += remnant;
} else {
assert(remnant >= MIN_BUDGET);
/* split the head refill */
REFILL_HEAD(sc).rAmount = remnant;
}
/* schedule the used amount */
/* set up a new replenishment structure */
refill_t new = (refill_t) {
.rAmount = usage, .rTime = REFILL_HEAD(sc).rTime + sc->scPeriod
};
refill_add_tail(sc, new);
if (refill_size(sc) == sc->scRefillMax || remnant < MIN_BUDGET) {
/* merge remnant with next replenishment - either it's too small
* or we're out of space */
if (refill_single(sc)) {
/* update inplace */
new.rAmount += remnant;
REFILL_HEAD(sc) = new;
} else {
refill_pop_head(sc);
REFILL_HEAD(sc).rAmount += remnant;
schedule_used(sc, new);
}
assert(refill_ordered(sc));
} else {
/* leave remnant as reduced replenishment */
assert(remnant >= MIN_BUDGET);
/* split the head refill */
REFILL_HEAD(sc).rAmount = remnant;
schedule_used(sc, new);
}
REFILL_SANITY_END(sc);
}
void refill_unblock_check(sched_context_t *sc)
{
if (isRoundRobin(sc)) {
/* nothing to do */
return;
}
/* advance earliest activation time to now */
REFILL_SANITY_START(sc);
if (refill_ready(sc)) {
@ -323,14 +347,7 @@ void refill_unblock_check(sched_context_t *sc)
}
}
/* it's possible that a refill is not bigger than min budget (if a task
* uses less than min budget, it will still be scheduled for refill), if
* so merge with the next refill, as it's not enough to schedule the task. */
if (!refill_sufficient(sc, 0)) {
assert(!refill_single(sc));
refill_t insufficient = refill_pop_head(sc);
REFILL_HEAD(sc).rAmount += insufficient.rAmount;
}
assert(refill_sufficient(sc, 0));
}
REFILL_SANITY_END(sc);
}

View file

@ -50,6 +50,7 @@ static inline bool_t PURE isSchedulable(const tcb_t *thread)
{
return isRunnable(thread) &&
thread->tcbSchedContext != NULL &&
thread->tcbSchedContext->scRefillMax > 0 &&
!thread_state_get_tcbInReleaseQueue(thread->tcbState);
}
#else
@ -114,8 +115,9 @@ void restart(tcb_t *target)
cancelIPC(target);
#ifdef CONFIG_KERNEL_MCS
setThreadState(target, ThreadState_Restart);
if (likely(target->tcbSchedContext != NULL)) {
schedContext_resume(target->tcbSchedContext);
schedContext_resume(target->tcbSchedContext);
if (isSchedulable(target)) {
possibleSwitchTo(target);
}
#else
setupReplyMaster(target);
@ -330,9 +332,8 @@ static void switchSchedContext(void)
}
/* if a thread doesn't have enough budget, it should not be in the scheduler */
if (!refill_ready(NODE_STATE(ksCurSC)) || !refill_sufficient(NODE_STATE(ksCurSC), 0)) {
assert(!thread_state_get_tcbQueued(NODE_STATE(ksCurSC)->scTcb->tcbState));
}
assert((refill_ready(NODE_STATE(ksCurSC)) && refill_sufficient(NODE_STATE(ksCurSC), 0))
|| !thread_state_get_tcbQueued(NODE_STATE(ksCurSC)->scTcb->tcbState));
NODE_STATE(ksCurSC) = NODE_STATE(ksCurThread)->tcbSchedContext;
}
@ -578,8 +579,31 @@ void setNextInterrupt(void)
setDeadline(next_interrupt - getTimerPrecision());
}
void chargeBudget(ticks_t capacity, ticks_t consumed)
{
if (isRoundRobin(NODE_STATE(ksCurSC))) {
assert(refill_size(NODE_STATE(ksCurSC)) == MIN_REFILLS);
REFILL_HEAD(NODE_STATE(ksCurSC)).rAmount += REFILL_TAIL(NODE_STATE(ksCurSC)).rAmount;
REFILL_TAIL(NODE_STATE(ksCurSC)).rAmount = 0;
} else {
refill_budget_check(NODE_STATE(ksCurSC), consumed, capacity);
}
assert(REFILL_HEAD(NODE_STATE(ksCurSC)).rAmount >= MIN_BUDGET);
NODE_STATE(ksConsumed) = 0;
if (likely(isRunnable(NODE_STATE(ksCurThread)))) {
endTimeslice();
rescheduleRequired();
}
}
void endTimeslice(void)
{
if (unlikely(NODE_STATE(ksCurThread) == NODE_STATE(ksIdleThread))) {
return;
}
assert(isRunnable(NODE_STATE(ksCurSC->scTcb)));
if (refill_ready(NODE_STATE(ksCurSC)) && refill_sufficient(NODE_STATE(ksCurSC), 0)) {
/* apply round robin */
@ -645,15 +669,17 @@ void awaken(void)
{
while (unlikely(NODE_STATE(ksReleaseHead) != NULL && refill_ready(NODE_STATE(ksReleaseHead)->tcbSchedContext))) {
tcb_t *awakened = tcbReleaseDequeue();
/* the currently running thread cannot have just woken up */
assert(awakened != NODE_STATE(ksCurThread));
/* round robin threads should not be in the release queue */
assert(!isRoundRobin(awakened->tcbSchedContext));
/* threads should wake up on the correct core */
SMP_COND_STATEMENT(assert(awakened->tcbAffinity == getCurrentCPUIndex()));
refill_unblock_check(awakened->tcbSchedContext);
if (unlikely(!refill_ready(awakened->tcbSchedContext))) {
tcbReleaseEnqueue(awakened);
} else {
assert(refill_sufficient(awakened->tcbSchedContext, 0));
tcbSchedAppend(awakened);
possibleSwitchTo(awakened);
}
/* threads HEAD refill should always be > MIN_BUDGET */
assert(refill_sufficient(awakened->tcbSchedContext, 0));
possibleSwitchTo(awakened);
/* changed head of release queue -> need to reprogram */
NODE_STATE(ksReprogram) = true;
}
}
#endif

View file

@ -135,10 +135,21 @@ static exception_t invokeSchedContext_Unbind(sched_context_t *sc)
return EXCEPTION_NONE;
}
#ifdef ENABLE_SMP_SUPPORT
static inline void maybeStallSC(sched_context_t *sc)
{
if (sc->scTcb) {
remoteTCBStall(sc->scTcb);
}
}
#endif
exception_t decodeSchedContextInvocation(word_t label, cap_t cap, extra_caps_t extraCaps)
{
sched_context_t *sc = SC_PTR(cap_sched_context_cap_get_capSCPtr(cap));
SMP_COND_STATEMENT((maybeStallSC(sc));)
switch (label) {
case SchedContextBind:
return decodeSchedContext_Bind(sc, extraCaps);
@ -160,7 +171,6 @@ void schedContext_resume(sched_context_t *sc)
assert(!sc || sc->scTcb != NULL);
if (likely(sc) && isSchedulable(sc->scTcb)) {
assert(sc->scTcb != NULL);
refill_unblock_check(sc);
if (isRunnable(sc->scTcb) && sc->scRefillMax > 0) {
if (!(refill_ready(sc) && refill_sufficient(sc, 0))) {
@ -179,10 +189,10 @@ void schedContext_bindTCB(sched_context_t *sc, tcb_t *tcb)
tcb->tcbSchedContext = sc;
sc->scTcb = tcb;
#if CONFIG_MAX_NUM_NODES > 1
#ifdef ENABLE_SMP_SUPPORT
if (tcb->tcbAffinity != sc->scCore) {
if (isSchedulable(tcb)) {
SMP_COND_STATEMENT(remoteTCBStall(tcb));
remoteTCBStall(tcb);
tcbSchedDequeue(tcb);
}
migrateTCB(tcb, sc->scCore);

View file

@ -19,22 +19,35 @@
static exception_t invokeSchedControl_Configure(sched_context_t *target, word_t core, ticks_t budget, ticks_t period,
word_t max_refills)
{
/* don't modify parameters of tcb while it is in a sorted queue */
if (target->scTcb) {
/* possibly stall a remote core */
SMP_COND_STATEMENT(remoteTCBStall(target->scTcb));
/* remove from scheduler */
tcbReleaseRemove(target->scTcb);
tcbSchedDequeue(target->scTcb);
/* bill the current consumed amount before adjusting the params */
if (NODE_STATE_ON_CORE(ksCurSC, target->scCore) == target) {
ticks_t capacity = refill_capacity(target, NODE_STATE_ON_CORE(ksConsumed, target->scCore));
if (checkBudget()) {
commitTime();
} else {
chargeBudget(capacity, NODE_STATE_ON_CORE(ksConsumed, target->scCore));
}
}
}
if (budget == period) {
/* this is a cool hack: for round robin, we set the
* period to 0, which means that the budget will always be ready to be refilled
* and the code doesn't need special casing
* and avoids some special casing.
*/
period = 0;
max_refills = MIN_REFILLS;
}
if (core == target->scCore && target->scRefillMax > 0 && target->scTcb && isRunnable(target->scTcb)) {
if (SMP_COND_STATEMENT(core == target->scCore &&) target->scRefillMax > 0 && target->scTcb
&& isRunnable(target->scTcb)) {
/* the scheduling context is active - it can be used, so
* we need to preserve the bandwidth */
refill_update(target, period, budget, max_refills);
@ -42,19 +55,21 @@ static exception_t invokeSchedControl_Configure(sched_context_t *target, word_t
/* the scheduling context isn't active - it's budget is not being used, so
* we can just populate the parameters from now */
refill_new(target, max_refills, budget, period);
if (core != target->scCore && target->scTcb) {
/* if the core changed and the SC has a tcb, the SC is getting
* budget - so migrate it */
target->scCore = core;
SMP_COND_STATEMENT(Arch_migrateTCB(target->scTcb));
SMP_COND_STATEMENT(target->scTcb->tcbAffinity = target->scCore;)
#ifdef ENABLE_SMP_SUPPORT
target->scCore = core;
if (target->scTcb && target->scTcb->tcbAffinity != target->scCore) {
migrateTCB(target->scTcb, target->scCore);
}
#endif /* ENABLE_SMP_SUPPORT */
}
if (target->scTcb && isRunnable(target->scTcb) && target->scRefillMax > 0) {
if (target->scTcb && target->scRefillMax > 0) {
schedContext_resume(target);
possibleSwitchTo(target->scTcb);
if (target->scTcb == NODE_STATE(ksCurThread)) {
rescheduleRequired();
} else if (isRunnable(target->scTcb)) {
possibleSwitchTo(target->scTcb);
}
}
return EXCEPTION_NONE;
@ -76,7 +91,7 @@ static exception_t decodeSchedControl_Configure(word_t length, cap_t cap, extra_
time_t budget_us = mode_parseTimeArg(0, buffer);
time_t period_us = mode_parseTimeArg(TIME_ARG_SIZE, buffer);
word_t max_refills = MIN_REFILLS + getSyscallArg(TIME_ARG_SIZE * 2, buffer);
word_t max_refills = getSyscallArg(TIME_ARG_SIZE * 2, buffer);
cap_t targetCap = extraCaps.excaprefs[0]->cap;
if (unlikely(cap_get_capType(targetCap) != cap_sched_context_cap)) {

View file

@ -88,7 +88,6 @@ void tcbSchedEnqueue(tcb_t *tcb)
#ifdef CONFIG_KERNEL_MCS
assert(isSchedulable(tcb));
assert(refill_sufficient(tcb->tcbSchedContext, 0));
assert(refill_ready(tcb->tcbSchedContext));
#endif
if (!thread_state_get_tcbQueued(tcb->tcbState)) {