Ucos the basis for multi-tasking consists of several aspects: Task control block, task stack, interrupt, task priority, and so on.
First, the structure of the task control block is as follows
When the system runs a task, it gets the task control block according to the priority of the task, and then obtains the task code pointer in the task stack.
typedef struct OS_TCB {//Task control block
OS_STK *ostcbstkptr; /* Pointer to top of task stack stack */
#if os_task_create_ext_en > 0u
void *ostcbextptr; /* Pointer to the task control block extension */
OS_STK *ostcbstkbottom; /* Pointer to the bottom of the task stack */
INT32U ostcbstksize; /* Length of the task stack */
int16u ostcbopt; /* Select item when creating a task */
int16u Ostcbid; /* The domain is not currently in use */
#endif
struct OS_TCB *ostcbnext; /* Pointer to the back of a task control block */
struct OS_TCB *ostcbprev; /* Pointer to the previous task control block */
#if (os_event_en)
Os_event *ostcbeventptr; /* */
#endif
#if (os_event_en) && (Os_event_multi_en > 0u)
Os_event **ostcbeventmultiptr; /* Pointer to the event control block */
#endif
#if ((Os_q_en > 0u) && (Os_max_qs > 0u)) | | (Os_mbox_en > 0u)
void *ostcbmsg; /* Point to the pointer passed to the task message */
#endif
#if (Os_flag_en > 0u) && (Os_max_flags > 0u)
#if os_task_del_en > 0u
Os_flag_node *ostcbflagnode; /* Pointer to Event flag node */
#endif
Os_flags Ostcbflagsrdy; /* Event flag Settings make task ready to execute */
#endif
INT32U ostcbdly; /* Number of Beats waiting on task */
Int8u Ostcbstat; /* The current status flag for the task */
The task status has the following list
/******************************************
Os_stat_rdy Status Ready
Os_stat_sem Waiting Signal Volume
Os_stat_mbox Waiting for message mailbox
Os_stat_q waiting for Message Queuing
Os_stat_suspend Task hangs
Os_stat_mutex waiting for mutex signal volume
Os_stat_flag Wait Sign
Os_stat_multi wait for more that what, still don't know
************************************************/
Int8u Ostcbprio; /* Priority level of the task */
Int8u OSTCBX; /* Data for quick access to ready tables */
Int8u Ostcby; /* Quick access to Ready table data */
Os_prio Ostcbbitx; /* Quick access to Ready table data */
Os_prio ostcbbity; /* Quick access to Ready table data */
#if os_task_del_en > 0u
Int8u Ostcbdelreq; /* Flag requested when deleting a task */
#endif
#if os_task_profile_en > 0u//This is used to monitor the execution status of a task.
INT32U ostcbctxswctr; /* The number of times the task is switched to */
INT32U Ostcbcyclestot; /* Total number of Beats running on the task */
INT32U Ostcbcyclesstart; /* Fast clock cycle at start of task */
OS_STK *ostcbstkbase; /* Start position of the task stack */
INT32U ostcbstkused; /* Number of stacks already in use */
#endif
#if os_task_name_en > 0u
int8u *ostcbtaskname;//Task TCB's name string pointer
#endif
#if os_task_reg_tbl_size > 0u
INT32U ostcbregtbl[os_task_reg_tbl_size];//here should be a quick save data for the task register
#endif
} OS_TCB;
This structure has more than the macro definition of open variables, for the time being not discussed, mainly have these several more important
OS_STK *ostcbstkptr; /* Pointer to top of task stack stack */
struct OS_TCB *ostcbnext; /* Pointer to the back of a task control block */
struct OS_TCB *ostcbprev; /* Pointer to the previous task control block */
Int8u Ostcbprio; /* Priority level of the task */
Why there is no pointer to the task code, this is because the task code is stored in the stack area of the operating system, we know, for the task, the task code pointer actually refers to the execution of this code, the processor's PC pointer, when the system is interrupted, the pointer automatically saved, after the execution of the interrupt automatic recovery, Execution of the original process, the principle of ucos is to design a system-level interrupt, the timing of the interruption, the execution of the interruption and automatic recovery process changes into a task switching process, the switching process to restore our own task stack to the actual CPU stack, Automatically switch to a new task to achieve multitasking. Visible, the task code is exactly what should be placed on the stack, followed by the code.
In addition, the operating system's task control block is not a dynamic application, but the compile time has been determined how many, as follows
Os_ext OS_TCB ostcbtbl[os_max_tasks + os_n_sys_tasks]; /* Table of TCBs */
Os_max_tasks and os_n_sys_tasks are defined by the Os_cfg file, the previous refers to the maximum number of system tasks, the latter is the number of system retention tasks, the system has only a few of these task control blocks, so up to so many tasks, There is also an associated global variable
Os_ext OS_TCB *ostcbpriotbl[os_lowest_prio + 1u];
This variable will save a pointer to all the task control blocks already set in the system (that is, create Task), his size is the maximum system priority, Ucos does not allow the priority to repeat the reason is here, he will be the system's task control block in the form of priority in this array, so, When switching tasks, it is not necessary to poll the task control block list, but to get the task priority immediately after getting the task control block in the Ostcbpriotbl table, the efficiency is much faster (not just a lot of problems, real-time system requirements code running efficiency is predictable, The time to poll the list is not deterministic, it may be found for the first time, or it may not be found at the end.
There are also several necessary variables
Os_ext OS_TCB *ostcbcur;
Os_ext OS_TCB *ostcbfreelist;
Os_ext OS_TCB *ostcbhighrdy;
Os_ext OS_TCB *ostcblist;
Ostcbcur identifies the currently running TCB block, ostcbfreelist the free TCB block chain header pointer in all TCB in the system, Ostcbhighrdy the highest priority TCB block currently ready, the target of the next switch, Ostcblist System effective TCB block's chain header pointer
As we have seen before, there is a pointer to next in the TCB variable structure and a prev pointer, which is used to construct the linked list, which is constructed when the system is initialized, but first we need to understand one thing, regardless of whether the linked list forms a divine horse structure, The actual data elements are still stored in the OSTCBTBL array, but only when the program is used to organize a linked list.
When the system is initialized, the program calls the Os_init function (external programming call), calls the Os_inittcblist function in the Os_init, implements the empty list initialization in the Os_inittcblist, as follows
static void Os_inittcblist (void)
{
Int8u IX;
Int8u Ix_next;
OS_TCB *PTCB1;
OS_TCB *PTCB2;
OS_MEMCLR ((int8u *) &ostcbtbl[0], sizeof (OSTCBTBL));
OS_MEMCLR ((int8u *) &ostcbpriotbl[0], sizeof (OSTCBPRIOTBL));
for (ix = 0u; IX < (os_max_tasks + os_n_sys_tasks-1u); ix++)
{
Ix_next = IX + 1u;
PTCB1 = &OSTCBTbl[ix];
PTCB2 = &OSTCBTbl[ix_next];
Ptcb1->ostcbnext = PTCB2;
#if os_task_name_en > 0u
Ptcb1->ostcbtaskname = (int8u *) (void *) "?";
#endif
}
PTCB1 = &OSTCBTbl[ix];
Ptcb1->ostcbnext = (OS_TCB *) 0;
#if os_task_name_en > 0u
Ptcb1->ostcbtaskname = (int8u *) (void *) "?";
#endif
Ostcblist = (OS_TCB *) 0; Ostcbfreelist = &OSTCBTbl[0]; }
You can see, enter this function, through a loop, all the elements in the ostcbtbl into a large linked list, the head of the list is ostcbfreelist, so that the empty task block list is initialized, and then the ostcblist assignment is null, wait for the task to be created
The function called when creating a task is ostaskcreate, and we analyze some of its structure
First, he's going to make a decision. First, you cannot create a task in an interrupt second, task priority cannot be duplicated
if (Ostcbpriotbl[prio] = = (OS_TCB *) 0)
As we said before, when a task is created, its TCB control block is placed in the corresponding position in the OSTCBPRIOTBL based on the priority of the task, then the data at that location will not be 0, at this point, if a new task is detected the priority of the creation of the TCB already has data, indicating that the priority is duplicated, cannot create
Two functions are then called
Ostaskstkinit (Task, P_arg, PTOs, 0u);
Os_tcbinit (Prio, PSP, (OS_STK *) 0, 0u, 0u, (void *) 0, 0u);
The first function is the function that we need to port in OS_CPU_C.C, which is related to the processor architecture, and a detailed view of the porting guide, with a focus on this sentence in Ostaskstkinit
* (Stk) = (int32u) 0x01000000l; /* XPSRXPSR T bit (24th bit) Set 1, otherwise the first time the task is performed fault*/
* (--STK) = (int32u) task; /* Entry POINTPC must point to the mission entrance.
The pointer to the task is stored in the stack, which matches the previous word.
After the stack area is set up, the TCB control block is initialized, and this section of code is longer, with several details.
First, the system should remove a control block from the idle control block and join the effective TCB control block, as follows
PTCB = Ostcbfreelist
if (PTCB! = (OS_TCB *) 0)
{
Ostcbfreelist = ptcb->ostcbnext;
Visible, the table header of the empty list is replaced by the second node, and the table header is used for subsequent operations, that is, the task control block used as the current task.
Ptcb->ostcbstkptr = PTOs;
Ptcb->ostcbprio = Prio;
Ptcb->ostcbstat = Os_stat_rdy;
Ptcb->ostcbstatpend = OS_STAT_PEND_OK;
ptcb->ostcbdly = 0u;
The stack top pointer, task priority, the stack has a task code pointer, to live, after the completion of some of the signal volume and so on after the operation (said later), came to this section
Ostcbpriotbl[prio] = PTCB;
Ptcb->ostcbnext = ostcblist;
Ptcb->ostcbprev = (OS_TCB *) 0;
if (ostcblist! = (OS_TCB *) 0)
{
Ostcblist->ostcbprev = PTCB;
}
Ostcblist = PTCB;
The control block pointer of the currently created task is placed in the OSTCBPRIOTBL, followed directly by priority, the new task control block is connected to the head of the task control block already existing in the system, thus completing an idle control block to the effective control block transfer, and creating the task, Wait for late call
In addition, UCOS defines an idle task to perform the task without a task, so the task must be of the lowest priority, otherwise he will preempt other priority tasks, the task function name
Os_taskidle
The task does nothing at all, in that similar idling run, called by Os_inittaskidle, while Os_inittaskidle is called by Os_init, which automatically creates the task when initializing the system
In addition to the idle task, also defined a statistical task, dedicated to statistical system implementation, such as CPU utilization, to monitor the system, you can then count the task hook function to do the operation of the system output, the relevant variable is oscpuusage
Ucos Task Control block detailed