struct os_tcb *OSTCBNext; /* Pointer to next TCB in the TCB list*/ struct os_tcb *OSTCBPrev; /* Pointer to previous TCB in the TCB list*/ //这两个是任务控制块指针,最后这些任务的控制块是链接成双向链表的,以便于查找和修改任务控制块。 #if OS_EVENT_EN OS_EVENT *OSTCBEventPtr; /* Pointer to event control block*/ #endif
#if ((OS_Q_EN > 0) && (OS_MAX_QS > 0)) || (OS_MBOX_EN > 0) void *OSTCBMsg; /* Message received from OSMboxPost() or OSQPost()*/ #endif
#if (OS_VERSION >= 251) && (OS_FLAG_EN > 0) && (OS_MAX_FLAGS > 0) #if OS_TASK_DEL_EN > 0 OS_FLAG_NODE *OSTCBFlagNode; /* Pointer to event flag node*/ #endif OS_FLAGS OSTCBFlagsRdy; /* Event flags that made task ready to run*/ #endif
INT16U OSTCBDly; /* Nbr ticks to delay task or, timeout waiting for event*/ //这个是延时的ticks数量,ticks是每秒定时器产生的中断数量,一般是每秒1000个ticks。也就是每秒产生1000个定时器中断。这个变量是用来记忆一个任务延时的ticks的,比如一个任务自己想延时1s钟,那这个变量就要赋值1000. INT8U OSTCBStat; /* Task status */ //任务的状态,用于记忆任务是运行态,就绪态,还是…… BOOLEAN OSTCBPendTO; /* Flag indicating PEND timed out (TRUE == timed out)*/ INT8U OSTCBPrio; /* Task priority (0 == highest, 63 == lowest) */ //这个是任务优先级,这个ucos是根据优先级进行调度的,优先级是我们创建任务时赋给任务的一个优先顺序值,在ucos中这个数值越小,优先级越高,比如优先级为3的任务和优先级为8的任务都就绪,那ucos首先运行任务3. 关于ucos高效的任务调度算法我们将在以下文章中详细讲解。 INT8U OSTCBX; /* Bit position in group corresponding to task priority (0..7) */ INT8U OSTCBY;/* Index into ready table corresponding to task priority */ INT8U OSTCBBitX; /* Bit mask to access bit position in ready table */ INT8U OSTCBBitY;/* Bit mask to access bit position in ready group*/ //上述四个变量是和高效率调度任务有关的。 #if OS_TASK_DEL_EN > 0 INT8U OSTCBDelReq;/* Indicates whether a task needs to delete itself*/ #endif
#if OS_TASK_PROFILE_EN > 0 INT32U OSTCBCtxSwCtr; /* Number of time the task was switched in */ INT32U OSTCBCyclesTot; /* Total number of clock cycles the task has been running*/ INT32U OSTCBCyclesStart; /* Snapshot of cycle counter at start of task resumption*/ OS_STK *OSTCBStkBase; /* Pointer to the beginning of the task stack */ INT32U OSTCBStkUsed; /* Number of bytes used from the stack */ #endif #if OS_TASK_NAME_SIZE > 1 char OSTCBTaskName[OS_TASK_NAME_SIZE]; #endif } OS_TCB; 关于这个任务控制块,这里只是做一下简单的说明,如果有什么不理解的地方没有关系,只要知道定义这个TCB结构体的目的就行。我们会在下面的程序分析中详细地说明的。
前面老是说任务切换和任务调度,我说一下这两个概念的区别,任务调度就是决定要执行那个任务。比如现在有优先级为2,15,34的任务就绪,那任务调度要找出优先级最高的任务,即任务2,这个任务将要运行。而任务切换就是在合适的时间里将当前正在运行的任务保存进度,转而去执行调度程序得到的最高优先级的任务2。这也就是切换的真正含义。
下面我们到OSInit()这个函数内部去看看它具体怎么初始化的,
下面贴代码:
void OSInit (void)
{
#if OS_VERSION >= 204
OSInitHookBegin(); /* Call port specific initialization code */
#endif
OS_InitMisc(); /* Initialize miscellaneous variables */
OS_InitRdyList(); /* Initialize the Ready List */
OS_InitTCBList(); /* Initialize the free list of OS_TCBs */
OS_InitEventList(); /* Initialize the free list of OS_EVENTs */
……………………
OS_InitTaskIdle();
看代码就知道这个文件实现了对全局杂项变量的初始化,就绪表的初始化,任务控制块的初始化,初始化空闲任务等工作,当然还有其他的初始化操作,这些和我们的操作系统核心内容关系就不是很多了,我们尽量精简这个ucos,只展现其核心内容,让大家明白ucos操作系统是怎么实现对处理机调度的。即多任务实时操作系统到底是怎么实现的。
所谓ucos的初始化就是对那些核心的全局变量进行清零工作,使其处于可知的状态。
OSIntNesting = 0; /* Clear the interrupt nesting counter */
//这个全局变量是用于记录中断嵌套层数的
OSLockNesting = 0; /* Clear the scheduling lock counter */
//这个全局变量是给任务上锁的标志
OSTaskCtr = 0; /* Clear the number of tasks */
//这个变量用于记录系统中的任务数量
OSRunning = FALSE; /* Indicate that multitasking not started */
//这个变量用于标志ucos的运行状态的
OSCtxSwCtr = 0; /* Clear the context switch counter */
//这个变量用于记录系统进行任务切换的次数的
OSIdleCtr = 0L; /* Clear the 32-bit idle counter */
//这个是空闲任务用于计数的变量。空闲任务是这样一种任务,在没有任何可执行的用户任务的时候,就要执行空闲任务,它什么也不干,只是让OSIdleCtr这个变量加一。因为cpu在加电后就不能停止执行指令,即是用户没有需要执行的任务,那也要执行一个空闲任务,只要cpu是按照我们的意愿去执行程序,那什么就都在我们的掌握之中,是吧。
下面开始初始化就绪表的相关变量。
static void OS_InitRdyList (void)
{
INT8U i;
INT8U *prdytbl;
OSRdyGrp = 0x00; /* Clear the ready list */
prdytbl = &OSRdyTbl[0];
for (i = 0; i < OS_RDY_TBL_SIZE; i++) {
*prdytbl++ = 0x00;
}
//上述代码是把就绪表的相关变量清零。
OSPrioCur = 0;
//这个变量是当前任务的优先级
OSPrioHighRdy = 0;
//这个是当前最高的优先级
OSTCBHighRdy = (OS_TCB *)0;
//最高优先级的任务控制块
OSTCBCur = (OS_TCB *)0;
//当前优先级的任务控制块
} |