gogoWebsite

UCOS II Multitasking Switching Routine (II)

Updated to 2 hours ago

Original link: http:///detail/


five. Task status:
uCOS II mainly has five task states, the sleep state is the suspend state, and the blocking state and the delay state are unified as the waiting state. Added an interrupted state. UC/OS-II always creates an idle task that is put into operation when no other tasks enter the ready state. This idle task [OSTaskIdle()] is always set to the lowest priority idle task OSTaskIdle() does nothing, but just keeps adding 1 to a 32-bit counter called OSIdleCtr. The statistics task uses this counter to determine the actual CPU time consumed by the current application software. Idle tasks cannot be deleted by the application software.
DORMANT refers to the task resides in the program space and has not been handed over to μC/OS-II for management. Handling the task to μC/OS-II is by calling one of the following two functions: OSTaskCreate() or OSTaskCreateExt(). Once the task is established, the task enters ready to run. Task establishment can be either before multitasking starts or dynamically established by a running task. If a task is established by another task and the priority of this task is higher than the task that established it, the newly established task will immediately gain control of the CPU. A task can return to sleep by calling OSTaskDel(), or bring another task into sleep by calling the function.
Calling OSStart() can start multitasking. The OSStart() function runs the task with the highest priority entering the ready state. Ready tasks can only enter the running state when all tasks with priority higher than this task turn into a waiting state or are deleted.
A running task can delay itself for a period of time by calling one of two functions, either OSTimeDly() or OSTimeDlyHMSM(). This task then enters a waiting state. When this period of time passes, the next task with the highest priority and entering the ready state is immediately given control of the CPU. After the waiting time has passed, the system service function OSTimeTick() causes the delayed task to enter the ready state (see Section 3.10, clock beat).
The running task also needs to wait when it expects a certain event to occur. The method is to call one of the following 3 functions: OSSemPend(), OSMboxPend(), or OSQPend(). After the call, the task enters a waiting state (WAITING). When the task is suspended due to a waiting event (Pend), the next task with the highest priority immediately gains control of the CPU. When the event occurs, the suspended task enters the ready state. The report of the event may come from another task or from an interrupted service subroutine.
A running task can be interrupted unless the task is interrupted or μC/OS-II is interrupted. The interrupted task enters the Interrupted State of Service (ISR). When responding to an interrupt, the executing task is suspended, and the interrupt service subroutine controls the CPU's usage rights. An interrupt service subroutine may report the occurrence of one or more events, causing one or more tasks to enter a ready state. In this case, before returning from the interrupt service subroutine, μC/OS-II must determine whether the interrupted task is still the highest priority among the ready task. If the interrupt service subroutine causes a higher priority task to enter the ready state, the newly entered the ready state with a higher priority task will be run, otherwise the originally interrupted task can continue to run.
When all tasks are waiting for the event to occur or waiting for the delay time to end, μC/OS-II executes idle task and executes the OSTaskIdle() function.
six. Task Switching:
Context Switch is translated into context switch in some books, and its actual meaning is task switch, or CPU register content switch. When the multitasking kernel decides to run another task, it saves the current state (Context) of the running task, that is, all contents in the CPU register. These contents are stored in the Task’s Context Storage area, which is the task’s own stack area. (See Figure 2.2). After the stack entry work is completed, the current status of the next task to be run is reloaded from the stack of the task into the CPU registers and start the operation of the next task. This process is called task switching. The task switching process adds additional load to the application. The more internal registers the CPU is, the heavier the extra load. The time required to switch tasks depends on how many registers the CPU has to put on the stack. The performance of the real-time kernel should not be evaluated by how many task switching can be performed per second.

 

seven. Task Scheduling Analysis:
uCOS II provides the simplest real-time kernel task scheduling, with a simple algorithm, so it only supports priority preemption task scheduling, does not support time slice training scheduling algorithm, and does not support priority reversal.
uCOS II always runs the highest priority in the task that enters the ready state. Determine which task has the highest priority and which task is running below is done by the scheduler. Task-level scheduling is done by the function OSSched(). The scheduling of the interrupt level is done by another function OSIntExt(), which will be described later.
The time spent on uCOS II task scheduling is a constant and has nothing to do with the number of tasks established in the application.
In uCOS, we used to get OSTCBHighRdy first and then compare it with OSTCBCur. Because this comparison is a comparison of two pointer-type variables, this comparison is relatively slow in 8-bit and some 16-bit microprocessors. And in μC/OS-II is a comparison of two integers. Moreover, unless the user actually needs to do task switching, when checking the task control block priority table OSTCBPrioTbl[], there is no need to use pointer variables to check OSTCBHighRdy. Combining these two improvements, i.e. using integer comparison instead of pointer comparison and looking up tables when task switching is required, makes uCOS II faster than uCOS on 8-bit and some 16-bit microprocessors.
To implement task switching, OSTCBHighRdy must point to the task control block OS_TCB with the highest priority, which is achieved by assigning the element in the OSTCBPrioTbl[] array subscripted by OSPrioHighRdy to OSTCBHighRdy [L3.8(4)]. Finally, the macro calls OS_TASK_SW() to complete the actual task switching [L3.8(6)].
Task switching is simple, and is completed in the following two steps, pushing the microprocessor register of the suspended task onto the stack, and then reverting the register value of the higher priority task from the stack to the register. In uCOS II, the stack structure of the ready task always looks like an interrupt has just occurred, and all microprocessor registers are stored in the stack. In other words, everything that μC/OS-II runs the ready task is to do, just restore all CPU registers and run the interrupt return instruction. In order to do task switching, OS_TASK_SW() was run, artificially imitating an interrupt. Most microprocessors have soft interrupt instructions or trap instructions TRAP to implement the above operations. Interrupt service subroutine or trap handling (Trap hardler), also known as accident handling (Exception handler), must provide interrupt vectors to assembly language function OSCtxSw(). In addition to requiring OS_TCBHighRdy to point to the task that is about to be suspended, OSCtxSw() also needs to make the current task control block OSTCBCur point to the task that is about to be suspended.
All codes of OSSched () are critical segment codes. In the process of finding the highest priority task to enter the ready state, to prevent the interrupt service subroutine from setting the ready position of one or several tasks, the interrupt is turned off. To shorten the switching time, all OSSched() code can be written in assembly language. To increase readability, portability and minimize assembly language code, OSSched() is written in C.

 

Related functions for task switching: related to the CPU system and assembly is completed.
1. OSStartHighRdy() executes the highest priority task
2. OSCtxSw()     Context switch for completing the task
3. OSIntCtxSw()  Context switch after interruption
4. OSTickISR()   interrupt service program startup

 

eight. Initialization of uCOS II:
OSInit() creates an idle task, which is always ready. The priority of the idle task OSTaskIdle() is always set to the lowest.
The task control blocks (OS_TCBs) of these two tasks are linked together using a two-way linked list. OSTCBList points to the beginning of this linked list. When a task is created, the task is always placed at the beginning of the linked list. In other words, OSTCBList always points to the last task established. The end point of the chain points to the null character NULL (that is, zero).
Because both tasks are in the ready state, the corresponding bit in the ready task table OSRdyTbl[] is set to 1. Also, because the corresponding bits of these two tasks are on the same line of OSRdyTbl[], they belong to the same group, so only 1 bit in OSRdyGrp is set to 1.
uCOS II also initializes 4 empty data structure buffers, as shown in Figure F3.8. Each buffer is a one-way linked list, allowing uCOS II to quickly obtain or release elements from a buffer. The number of control blocks OS_TCB is automatically determined. Of course, it includes enough task control blocks to be allocated to statistical tasks and idle tasks.

 

uCOS IIKernel Scheduling Analysis

 

 

 vxWorksKernel Scheduling Analysis

 

 

1. Only priority-based preemptive scheduling algorithms are supported, and time slice training is not supported;

 

 

Use work queue workQword to schedule;

 

 

2. 64 priority levels, only 64 tasks can be created, and users can only create 56 tasks;

 

 

According to user specifications, dynamically allocate the stack and create as many tasks as possible;

 

 

3. Each task has different priority.

 

 

 

 

 4. Priority reversal is not supported;

 

 

Support priority reversal, TCB saves two priorities;

 

 

5. The READY queue implements fast query through memory map tables. Very efficient;

 

 

Support task scheduling methods for preemption and time slice training;

 

 

6. Support clock beats;

 

 

Support for multi-cpu architecture is achieved through compilation switches.

 

 

7. Supports semaphores, message queues, event control blocks, event flag groups, message mailbox task communication mechanisms;

 

 

The queue is implemented using FIFO or priority two-way linked list;

 

 

8. Support interrupt nesting, the number of interrupt nesting layers can reach 255 layers, and interrupts use the stack of the current task to save the context;

 

 

Support interrupt nesting, interrupts use a dedicated stack to save context;

 

 

9. Each task has its own stack, and the stack size is set by the user;

 

 

Tasks are based on classes and objects management methods;

 

 

10. Support dynamic modification of task priority;

 

 

Support dynamic modification of task priority;

 

 

11. The task TCB is a static array. The establishment of a task is just to obtain a TCB from it, without dynamic allocation, and freeing memory;

 

 

The TCB of the task is saved in the task stack;

 

 

12. The task stack is created statically or dynamically by the user and is completed outside of the task creation. The task creation itself does not perform dynamic memory allocation;

 

 

Each task has its own stack, and the stack size is set by the user;

 

 

13. The total number of tasks (OS_MAX_TASKS) is determined by the user;

 

 

 

 

14. 0 has the highest priority and 63 has the lowest priority;

 

 

The priority of tasks is from 0-255, and the priority of 0 is the highest, allowing multiple tasks to be the same priority;

 

 

15. There is an idle task with the lowest priority, which runs when no user tasks are running.

 

 

There are no idle tasks to execute in the system;