ucOS的数据结构中最核心的一个数据结构就是任务控制块数据结构,其他的数据类型都是围绕该数据结构展开的,任务切换,代码调度也都是以该数据结构为基础来完成的。认清了该数据结构就了解了ucOS的运行机制。任务控制块数据结构如下:
typedef struct os_tcb {
OS_STK *OSTCBStkPtr; /* Pointer to current top of stack */
#if OS_TASK_CREATE_EXT_EN > 0
void *OSTCBExtPtr; /* Pointer to user definable data for TCB extension */
OS_STK *OSTCBStkBottom; /* Pointer to bottom of stack */
INT32U OSTCBStkSize; /* Size of task stack (in number of stack elements) */
INT16U OSTCBOpt; /* Task options as passed by OSTaskCreateExt() */
INT16U OSTCBId; /* Task ID (0..65535) */
#endif
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_FLAG_EN > 0)
OS_EVENT *OSTCBEventPtr; /* Pointer to event control block */
#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; /* Message received from OSMboxPost() or OSQPost() */
#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; /* Event flags that made task ready to run */
#endif
INT16U OSTCBDly; /* Nbr ticks to delay task or, timeout waiting for event */
INT8U OSTCBStat; /* Task status */
INT8U OSTCBStatPend; /* Task PEND status */
INT8U OSTCBPrio; /* Task priority (0 == highest) */
INT8U OSTCBX; /* Bit position in group corresponding to task priority */
INT8U OSTCBY; /* Index into ready table corresponding to task priority */
#if OS_LOWEST_PRIO <= 63
INT8U OSTCBBitX; /* Bit mask to access bit position in ready table */
INT8U OSTCBBitY; /* Bit mask to access bit position in ready group */
#else
INT16U OSTCBBitX; /* Bit mask to access bit position in ready table */
INT16U OSTCBBitY; /* Bit mask to access bit position in ready group */
#endif
#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
INT8U OSTCBTaskName[OS_TASK_NAME_SIZE];
#endif
} OS_TCB;
其中
OSTCBStkPtr--任务栈的指针,在任务中使用到的所有零时变量(包括任务切换时需要保存的上下文)都保存在OSTCBStkPtr指向的存储区域
OSTCBExtPtr--任务扩展数据信息指针,目前我理解这一部分主要用于保存任务名字的ASCII码
OSTCBStkBottom--任务栈底指针
OSTCBStkSize--任务栈的大小
OSTCBNext--任务控制块链表中的下一任务指针
OSTCBPrev--任务控制块链表中的上一任务指针
OSTCBEventPtr--任务等待时间指针,该数据结构本身是属于一个事件的,任务也只是属于事件的一个候选资源
OSTCBEventMultiPtr--互斥信号量指针
OSTCBMsg--邮箱指针
任务私有栈--是任务执行过程或者任务数据切换过程用于存放零时数据的一片内存区域
任务链表--为了便于管理ucOS将多个任务用链表的方式串接起来,这个链表称为任务链表
空任务链表--也是为了便于内存分配,ucOS在编译的时候就决定了整个系统最多支持多少个任务,同时就为这些任务预留了相应的任务控制块,这部分任务控制块就被称为空任务链表。在真正需要使用任务的时候,将从空任务链表中获取任务控制块到任务控制链表中
当前运行任务指针--指向当前正在运行的任务控制块
任务链表索引--为了更快的查找任务链表,ucOS建立了一个指向所有任务控制块的数组,这个数组就是任务链表索引。该索引以优先级排序
任务就绪表--已经就绪的任务表
任务就绪表索引
任务就绪表辅助登记表--一下三张表都是ucOS为了查找任何一个任务都使用相同的查找时间使用的额外表,它们的唯一作用就是保证系统的时效性
任务就绪表辅助注销表
任务就绪表辅助查找表
全局变量不完全统计:
OSLockNesting
OSIntNesting
OSCtxSwCtr
OSPrioHighRdy
OSPrioCur
OSTCBHighRdy
OSTCBCur
OSTaskCtr
OSRunning