This is a piece of information about the Ucos scheduler.
The implementation of Ucos Scheduler is mainly by a function os_sched
This function divides the scheduler's behavior into two parts, the first is the dispatch part, the second is the task switching part, as follows
void os_sched (void)
{
#if Os_critical_method = = 3u
Os_cpu_sr cpu_sr = 0u;
#endif
Os_enter_critical ();
if (osintnesting = = 0u) {
if (oslocknesting = = 0u) {
Os_schednew ();
Ostcbhighrdy = Ostcbpriotbl[ospriohighrdy];
if (Ospriohighrdy! = ospriocur) {
#if os_task_profile_en > 0u
ostcbhighrdy->ostcbctxswctr++;
#endif
osctxswctr++;
OS_TASK_SW ();
}
}
}
Os_exit_critical ();
}
This code uses two of all variables, namely
Osintnesting
Oslocknesting
The first variable when the system is interrupted call Osintenter +1, the exit interrupt when using Osintexit to make 1, so that the scheduling system is not interrupted, os_enter_critical This code shut down the interrupt,
The second variable is a dispatch lock, which is made by Osschedlock +1 Osschedunlock-1, which is used to temporarily mask the operation of the scheduler in the system.
At this point, you can see that when the scheduling occurs, the system is in a non-disruptive and the scheduler does not lock the case, call the Os_schednew function, the function part of the source code for
y = osunmaptbl[osrdygrp];
Ospriohighrdy = (int8u) ((y << 3u) + osunmaptbl[osrdytbl[y]);
There are also some source code is the same function, only 63 priority scale to 255 priority, the process of finding a ready table changes
Ospriohighrdy represents the priority of the highest-priority tasks currently in the system, finds the highest-priority (prepared) system TCB by priority, and ensures that it is not the priority of the currently running task, and then jumps to OS_TASK_SW for task switching
OS_TASK_SW is a task switch macro, expanded to be the OSCTXSW function, is required to implement the user interface code, as follows
Osctxsw
PUSH {R4, R5}
LDR R4, =nvic_int_ctrl; triggering PENDSV exception (causes context switch)
LDR R5, =nvic_pendsvset
STR R5, [R4]
POP {R4, R5}
BX LR
This code starts with a PEND_SV exception, so it should be in the interrupt handler function.
Interrupt processing function is very long, there is no code, but its core function is to compare the current task priority and the highest ready task priority, the stack pointer to the PSP switch and the corresponding assignment operation (tcbcur), when the exit interrupt can be achieved when the task switch. Specifically, This function should complete seven functions
Saves the endpoint pointer of the current task to the current task stack
Save the contents of the processor's universal register to the task stack
Saves the current value of the task stack pointer of the terminated task to the ostcbstkptr of the task control block
Get the task control block for the task you want to run
is the task stack pointer for the processor to get the task to run through the task control block
Restores the data in the task stack pointer of the task to be run to the CPU he passed the register
Make the processor get a breakpoint pointer to the task to run
From here we can see that if a task has the highest priority, and the task itself does not release the resource, that is, the task itself does not modify the system-ready table, the task will be executed until more advanced tasks occur.
Speaking of which, why do I have to switch tasks in the terminal? The reason is that the PC pointer cannot be pressed into the stack by instruction, but the CPU can automatically push the PC into the stack in the event of an interrupt, and we have to get the PC pointer, only through the stack.
All of the above is in the normal situation of the task switch, Ucos in the interrupt environment can also be a task switch, this task switch is implemented by the function Osintexit function, the core code is as follows
if (osrunning = = os_true) {
Os_enter_critical ();
if (osintnesting > 0u) {
osintnesting--;
}
if (osintnesting = = 0u) {
if (oslocknesting = = 0u) {
Os_schednew ();
Ostcbhighrdy = Ostcbpriotbl[ospriohighrdy];
if (Ospriohighrdy! = ospriocur) {
#if os_task_profile_en > 0u
ostcbhighrdy->ostcbctxswctr++;
#endif
osctxswctr++;
OSINTCTXSW ();
}
Previously said, the exit interrupt call this function, will be OSIntNesting-1, then the processor will do a task switch, and the other place is consistent with the ossched () function, but the task switch is used when the switch function is the OSINTCTXSW function, the function prototype is as follows
Osintctxsw
PUSH {R4, R5}
LDR R4, =nvic_int_ctrl; triggering PENDSV exception (causes context switch)
LDR R5, =nvic_pendsvset
STR R5, [R4]
POP {R4, R5}
BX LR
NOP
is consistent with the previous OSCTXSW.
Through the above analysis, know the specific process of system scheduling, task switching time can be said to be two, the first is to call ossched and interrupt in Osintexit, and ossched call in the system where a check to know
To say more, in the case of not using the task synchronization characteristics, the most frequently caused task scheduling method is the ostimedly clock delay time, the final implementation of the task scheduling through the interruption completed.
Ucos Scheduler Detailed