Scheduling - Vanderbilt University

Report
Scheduling in µC/OS-III
Akos Ledeczi
EECE 354, Fall 2012
Vanderbilt University
Ready “List”
• Not a simple linked list of
tasks ordered by priority
• Priority bitmap:
– Helps quickly identify the
highest priority level that
has at least one task
ready to run
– Count Leading Zeros (CLZ)
instruction in many CPUs
• Actual list is an array of
ready lists: one for each
priority level
Ready “List”
OS Tasks:
Empty list:
Ready “List”
• Adding a task always
puts it at the end of
the list
Preemptive Scheduling: Direct Post
Preemptive Scheduling: Deferred Post
Scheduling Points
•
•
•
•
•
•
•
•
•
•
•
•
•
•
Post (unless call made with OS_OPT_POST_NO_SCHED)
Call delay
Pend (unless event has already occurred)
Abort pend (only by another task of course)
Task creation
Task deletion
Kernel object deletion (tasks pending on these become ready)
Priority change
Suspend
Resume (only by another task of course)
End of all nested ISRs (OSIntExit() instead of OSSched())
Scheduler unlock (only final unlock as locking the scheduler can be nested)
Yield in round robin scheduling
Explicitly calling the scheduler
Round Robin Scheduling
•
•
•
•
•
Time Slicing
Must call OSSchedRoundRobinCfg() to enable round robin scheduling
Yield
Time quanta can be set on a per task basis
Time quanta can be changed at run-time
Scheduling from Task Level
void OSSched (void)
{
Disable interrupts
if (OSIntNestingCtr > (OS_NESTING_CTR)0) {
return;
}
}
/* ISRs still nested?
/* only schedule when no nested ISRs
*/
*/
if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) {
return;
}
OSPrioHighRdy
= OS_PrioGetHighest();
OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr;
if (OSTCBHighRdyPtr == OSTCBCurPtr) {
Enable interrupts
return;
}
OSTaskCtxSwCtr++;
/* Scheduler locked?
/* Yes
*/
*/
/* Find the highest priority ready
*/
/* Increment context switch counter
*/
OS_TASK_SW();
Enable interrupts
/* Perform a task level context switch
*/
/* Current is still highest priority task? */
/* Yes ... no need to context switch
*/
Scheduling from Interrupt Level
void OSIntExit (void)
{
Disable interrupts
if (OSIntNestingCtr == (OS_NESTING_CTR)0) {
/* Prevent OSIntNestingCtr from wrapping
return;
}
OSIntNestingCtr--;
if (OSIntNestingCtr > (OS_NESTING_CTR)0) {
/* ISRs still nested?
Enable interrupts
/* Yes
return;
}
if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) {
/* Scheduler still locked?
Enable interrupts
/* Yes
return;
}
OSPrioHighRdy
= OS_PrioGetHighest();
/* Find highest priority
OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr;
/* Get highest priority task ready-to-run
if (OSTCBHighRdyPtr == OSTCBCurPtr) {
/* Current task still the highest priority?
Enable interrupts
/* Yes
return;
}
OSTaskCtxSwCtr++;
/* Keep track of the total number of ctx switches
OSIntCtxSw();
Enable interrupts
}
/* Perform interrupt level ctx switch
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
Round Robin Scheduling
#if OS_CFG_SCHED_ROUND_ROBIN_EN > 0u
void OS_SchedRoundRobin (OS_RDY_LIST *p_rdy_list)
{
OS_TCB
*p_tcb;
if (OSSchedRoundRobinEn != DEF_TRUE) {
return;
}
CPU_CRITICAL_ENTER();
p_tcb = p_rdy_list->HeadPtr;
if (p_tcb == (OS_TCB *)0) {
CPU_CRITICAL_EXIT(); return;
}
if (p_tcb == &OSIdleTaskTCB) {
CPU_CRITICAL_EXIT(); return;
}
if (p_tcb->TimeQuantaCtr > (OS_TICK)0) {
p_tcb->TimeQuantaCtr--;
}
if (p_tcb->TimeQuantaCtr > (OS_TICK)0) {
CPU_CRITICAL_EXIT(); return;
}
if (p_rdy_list->NbrEntries < (OS_OBJ_QTY)2) {
CPU_CRITICAL_EXIT(); return;
return;
}
/* Make sure round-robin has been enabled
*/
/* Decrement time quanta counter
*/
/* Task not done with its time quanta
*/
/* slice only if multiple tasks at same priority
*/
Round Robin Scheduling cont’d.
if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) {
CPU_CRITICAL_EXIT(); return;
}
/* Can't round-robin if the scheduler is locked
OS_RdyListMoveHeadToTail(p_rdy_list);
/* Move current OS_TCB to the end of the list
p_tcb = p_rdy_list->HeadPtr;
/* Point to new OS_TCB at head of the list
if (p_tcb->TimeQuanta == (OS_TICK)0) {
/* See if we need to use the default time slice
p_tcb->TimeQuantaCtr = OSSchedRoundRobinDfltTimeQuanta;
} else {
p_tcb->TimeQuantaCtr = p_tcb->TimeQuanta;
/* Load time slice counter with new time
}
CPU_CRITICAL_EXIT();
}
#endif
*/
*/
*/
*/
*/
Task Level Context Switch: Before
Must prepare stack
as if an interrupt
occurred
Task Level Context Switch: After
Registers are restored
from the new task’s
stack
It is a “simulated”
return from interrupt
ISR Level Context Switch: Before
Interrupt has already
caused registers to be
saved on the stack
ISR Level Context Switch: After

similar documents