uCOS-II系统内核的主要工作是对任务的管理和调度。在进行接下来的源码分析前,先来把任务这东西理一理。
1. 任务的引入
在公司的大型的软件研发项目中,通常项目经理会将该项目分解成多个功能模块,项目组内程序员分别负责其中一个,当这多个功能模块完成时候,就意味着整个项目进度接近完成。当然,在开发过程中,项目组内的程序员是同时在工作的,即所谓的“并行开发”,这将大大提高了项目完成效率。
在uCOS-II中,上述的“功能模块”就是“任务”,uCOS-II就是一个能对这些任务的运行进行调度、管理,从而实现并发方式执行这些任务的多任务操作系统。
2. 任务控制块
uCOS-II系统中的任务从代码上看,依旧是一个个c函数,但是作为该函数要成为能被操作系统调度管理的任务,就应该具有一个控制数据结构,这就是任务控制块。
任务的任务控制块(TCB)相当于一个任务的身份证,系统就是通过任务控制块来管理任务的,没有任务控制块的任务就不是一个任务,因为它不能被系统管理。当用户应用程序调用OSTackCreate()函数创建一个任务时,该函数就会对任务控制块中所有成员(记录任务的堆栈指针、任务的当前状态,任务优先级别)赋予该任务相关的数据,并记录在RAM中。
//位于ucos-ii/source/ucos_ii.c
typedef struct os_tcb {
OS_STK *OSTCBStkPtr; //指向任务的私有栈的栈顶
#if OS_TASK_CREATE_EXT_EN > 0 // 早期的ucos创建任务其属性非常简单,后期想赋予任务更多的属性时,
// 为了兼容老的代码,多了这个配置宏,让操作系统使用者自己决定使用新属性否,EXT理解为扩展的
void *OSTCBExtPtr; // 指向用户可定义的数据,这些数据是为TCB某些功能服务的
OS_STK *OSTCBStkBottom; // 指向任务的私有栈的栈底
INT32U OSTCBStkSize; // 栈元素的个数,假设栈中有100个元素,每个元素占据4字节,共400字节。OSTCBStkSize则为100 */
INT16U OSTCBOpt; // 可选项
INT16U OSTCBId; // 任务的ID,区分任务用
#endif
struct os_tcb *OSTCBNext; // 双向链表,指向下一个任务
struct os_tcb *OSTCBPrev; // 双向链表,指向上一个任务
#if (OS_EVENT_EN) || (OS_FLAG_EN > 0)
OS_EVENT *OSTCBEventPtr; // Even指的是两个任务间的通信,如信号量、消息盒子、Mutex等
#endif
#if (OS_EVENT_EN) && (OS_EVENT_MULTI_EN > 0)
OS_EVENT **OSTCBEventMultiPtr; /* Pointer to multiple event control blocks */
#endif
#if ((OS_Q_EN > 0) && (OS_MAX_QS > 0)) || (OS_MBOX_EN > 0)
void *OSTCBMsg; // 指向传递给任务消息的指针
#endif
#if (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; /* 让任务变为rdy的那个flag */ /* Event flags that made task ready to run */
#endif
INT16U OSTCBDly; /* 等待一个event所要的tick的数目,Nbr ticks to delay task or, timeout waiting for event */
INT8U OSTCBStat; // 任务的当前状态标志
INT8U OSTC