好文档 - 专业文书写作范文服务资料分享网站

uCOS-II源码详解

天下 分享 时间: 加入收藏 我要投稿 点赞

#if OS_ARG_CHK_EN > 0 if (prio > OS_LOWEST_PRIO) { return (OS_PRIO_INVALID); } #endif

OS_ENTER_CRITICAL(); if (OSIntNesting > 0) { OS_EXIT_CRITICAL();

return (OS_ERR_TASK_CREATE_ISR); }

if (OSTCBPrioTbl[prio] == (OS_TCB *)0) { OSTCBPrioTbl[prio] = (OS_TCB *)1; OS_EXIT_CRITICAL();

psp = (OS_STK *)OSTaskStkInit(task, p_arg, ptos, 0); err = OS_TCBInit(prio, psp, (OS_STK *)0, 0, 0, (void *)0, 0); if (err == OS_NO_ERR) { if (OSRunning == TRUE) { OS_Sched(); } } else {

OS_ENTER_CRITICAL();

OSTCBPrioTbl[prio] = (OS_TCB *)0; OS_EXIT_CRITICAL(); }

return (err); }

OS_EXIT_CRITICAL(); return (OS_PRIO_EXIST);

OS_LOWEST_PRIO在ucos-ii.h中被定义为63,表示Task的优先级从0到63,共64级。首先判断prio是否超过最低优先级,如果是,则返回OS_PRIO_INVALID错误。

然后调用OS_ENTER_CRITICAL(),进入临界段,在临界段中的代码执行不允许被中断。这个宏是用户自定义的,一般是进行关中断操作,例如在x86中的CLI等。这个宏和OS_EXIT_CRITICAL()相对应,这个宏表示离开临界段。 OSTaskCreate不允许在中断中调用,因此会判断OSIntNesting是否大于0,如果大于0,表示正在中断嵌套,返回OS_ERR_TASK_CREATE_ISR错误。 接着判断该prio是否已经有Task存在,由于uC/OS-II只支持每一个优先级一个Task,因此如果该prio已经有进程存在,OSTaskCreate会返回OS_PRIO_EXIST错误。

相反,如果该prio先前没有Task存在,则将OSTCBPrioTbl[prio]置1,表示该prio已被占用,然后调用OSTaskStkInit初始化堆栈,调用OS_TCBInit初始化TCB,如果OSRunning为TRUE表示OS正在运行,则调用OS_Sched进行进程调度;否则返回。

下面来看看OSTaskStkInit和OS_TCBInit这两个函数。

OSTaskStkInit是一个用户自定义的函数,因为uC/OS-II在设计时无法知道当前处理器在进行进程调度时需要保存那些信息,OSTaskStkInit就是初始化堆栈,让Task看起来就好像刚刚进入中断并保存好寄存器的值一样,当OS_Sched调度到该Task时,只需切换到该堆栈中,将寄存器值Pop出来,然后执行一个中断返回指令IRET即可。

OSTaskStkInit的原型如下:

OS_STK *OSTaskStkInit (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT16U opt)

和OSTaskCreate类似,task是进程入口地址,pdata是参数地址,ptos是堆栈指针,而opt只是作为一个预留的参数Option而保留。返回的是调整以后的堆栈指针。

在OSTaskStkInit中,一般是将pdata入栈,flag入栈,task入栈,然后将各寄存器依次入栈。

OS_TCBInit初始化TCB数据结构,下面只提取主要部分来看:

INT8U OS_TCBInit (INT8U prio, OS_STK *ptos, OS_STK *pbos, INT16U id, INT32U stk_size, void *pext, INT16U opt)

{

OS_TCB *ptcb;

OS_ENTER_CRITICAL(); ptcb = OSTCBFreeList; if (ptcb != (OS_TCB *)0) {

OSTCBFreeList = ptcb->OSTCBNext; OS_EXIT_CRITICAL(); ptcb->OSTCBStkPtr = ptos; ptcb->OSTCBPrio = prio;

ptcb->OSTCBStat = OS_STAT_RDY; ptcb->OSTCBPendTO = FALSE; ptcb->OSTCBDly = 0;

#if OS_TASK_CREATE_EXT_EN > 0 ptcb->OSTCBExtPtr = pext; ptcb->OSTCBStkSize = stk_size; ptcb->OSTCBStkBottom = pbos; ptcb->OSTCBOpt = opt; ptcb->OSTCBId = id; #else pext = pext;

stk_size = stk_size; pbos = pbos; opt = opt; id = id; #endif

#if OS_TASK_DEL_EN > 0

ptcb->OSTCBDelReq = OS_NO_ERR; #endif

ptcb->OSTCBY = (INT8U)(prio >> 3);

ptcb->OSTCBBitY = OSMapTbl[ptcb->OSTCBY]; ptcb->OSTCBX = (INT8U)(prio & 0x07);

ptcb->OSTCBBitX = OSMapTbl[ptcb->OSTCBX]; #if OS_EVENT_EN

ptcb->OSTCBEventPtr = (OS_EVENT *)0; #endif

OSTaskCreateHook(ptcb); OS_ENTER_CRITICAL(); OSTCBPrioTbl[prio] = ptcb; ptcb->OSTCBNext = OSTCBList; ptcb->OSTCBPrev = (OS_TCB *)0; if (OSTCBList != (OS_TCB *)0) { OSTCBList->OSTCBPrev = ptcb; }

OSTCBList = ptcb;

OSRdyGrp |= ptcb->OSTCBBitY;

OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX; OSTaskCtr++; OS_EXIT_CRITICAL(); return (OS_NO_ERR); }

OS_EXIT_CRITICAL(); return (OS_NO_MORE_TCB); }

首先调用OS_ENTER_CRITICAL进入临界段,首先从OSTCBFreeList中拿出一个TCB,如果OSTCBFreeList为空,则返回OS_NO_MORE_TCB错误。

然后调用OS_EXIT_CRITICAL离开临界段,接着对该TCB进行初始化: 将OSTCBStkPtr初始化为该Task当前堆栈指针; OSTCBPrio设置为该Task的prio;

OSTCBStat设置为OS_STAT_RDY,表示就绪状态;

OSTCBDly设置为0,当该Task调用OSTimeDly时会初始化这个变量为Delay的时钟数,然后Task转入OS_STAT_状态。这个变量在OSTimeTick中检查,如果大于0表示还需要进行Delay,则进行减1;如果等于零表示无须进行Delay,可以马上运行,转入OS_STAT_RDY状态。

OSTCBBitY和OSTCBBitX的作用我们在等会专门来讨论。

紧接着就要将该TCB插入OSTCBList列表中,先调用

OS_ENTER_CRITICAL进入临界段,将该TCB插入到OSTCBList成为第一个节点,然后调整OSRdyGrp和OSRdyTbl,(这两个变量一会和

OSTCBBitX/OSTCBBitY一起讨论),最后将OSTaskCtr计数器加一,调用OS_EXIT_CRITICAL退出临界段。

OSMapTbl和OSUnMapTbl

刚才我们看到TCB数据结构中的OSTCBBitX/OSTCBBitY以及

OSRdyGrp/OSRdyTbl的使用,这里专门来讨论讨论这几个变量的用法。

uCOS-II源码详解

#ifOS_ARG_CHK_EN>0if(prio>OS_LOWEST_PRIO){return(OS_PRIO_INVALID);}#endifOS_ENTER_CRITICAL();if(OSIntNesting>0){OS_EXIT_CRITICAL();return(OS_ERR_TASK_CREATE_ISR
推荐度:
点击下载文档文档为doc格式
3238q1yi364bptb10lzm
领取福利

微信扫码领取福利

微信扫码分享