μC/OS-II的任务管理
字节表示)就是该两项之和。
程序清单 L4.10 堆栈检验函数
INT8UOSTaskStkChk(INT8Uprio,OS_STK_DATA*pdata)
{
OS_TCB*ptcb;
OS_STK*pchk;
INT32Ufree;
INT32Usize;
pdata->OSFree=0;
pdata->OSUsed=0;
if(prio>OS_LOWEST_PRIOprio!=OS_PRIO_SELF){
return(OS_PRIO_INVALID);
}
OS_ENTER_CRITICAL();
if(prio==OS_PRIO_SELF){(1)
prio=OSTCBCur->OSTCBPrio;
}
ptcb=OSTCBPrioTbl[prio];
if(ptcb==(OS_TCB*)0){(2)
OS_EXIT_CRITICAL();
return(OS_TASK_NOT_EXIST);
}
if((ptcb->OSTCBOptOS_TASK_OPT_STK_CHK)==0){(3)
OS_EXIT_CRITICAL();
return(OS_TASK_OPT_ERR);
}
free=0; (4)
size=ptcb->OSTCBStkSize;
pchk=ptcb->OSTCBStkBottom;
OS_EXIT_CRITICAL();
#ifOS_STK_GROWTH==1
while(*pchk++==0){
free++;
}
#else
while(*pchk--==0){
free++;
}
#endif
pdata->OSFree=free*sizeof(OS_STK);(5)
pdata->OSUsed=(size-free)*sizeof(OS_STK);
return(OS_NO_ERR);
}
4.4删除任务,OSTaskDel()
有时候删除任务是很有必要的。删除任务,是说任务将返回并处于休眠状态(参看3.02,任务状态),并不是说任务的代码被删除了,只是任务的代码不再被μC/OS-Ⅱ调用。通过调用OSTaskDel()就可以完成删除任务的功能(如程序清单L4.11所示)。OSTaskDel()一开始应确保用户所要删除的任务并非是空闲任务,因为删除空闲任务是不允许的[L4.11(1)]。不过,用户可以删除statistic任务[L4.11(2)]。接着,OSTaskDel()还应确保用户不是在ISR例程中去试图删除一个任务,因为这也是不被允许的[L4.11(3)]。调用此函数的任务可以通过指定OS_PRIO_SELF参数来删除自己[L4.11(4)]。接下来OSTaskDel()会保证被删除的任务是确实存在的[L4.11(3)]。如果指定的参数是OS_PRIO_SELF的话,这一判断过程(任务是否存在)自然是可以通过的,但笔者不准备为这种情况单独写一段代码,因为这样只会增加代码并延长程序的执行时间。
程序清单 L4.11 删除任务
INT8UOSTaskDel(INT8Uprio)
{
OS_TCB*ptcb;
OS_EVENT*pevent;
if(prio==OS_IDLE_PRIO){(1)
return(OS_TASK_DEL_IDLE);
}
if(prio>=OS_LOWEST_PRIOprio!=OS_PRIO_SELF){(2)
return(OS_PRIO_INVALID);
}
OS_ENTER_CRITICAL();
if(OSIntNesting>0){(3)
OS_EXIT_CRITICAL();
return(OS_TASK_DEL_ISR);
}
if(prio==OS_PRIO_SELF){(4)
Prio=OSTCBCur->OSTCBPrio;
}
if((ptcb=OSTCBPrioTbl[prio])!=(OS_TCB*)0){(5)
if((OSRdyTbl[ptcb->OSTCBY]=~ptcb->OSTCBBitX)==0){(6)
OSRdyGrp=~ptcb->OSTCBBitY;
}
if((pevent=ptcb->OSTCBEventPtr)!=(OS_EVENT*)0){(7)
if((pevent->OSEventTbl[ptcb->OSTCBY]=~ptcb->OSTCBBitX)==0)
{
pevent->OSEventGrp=~ptcb->OSTCBBitY;
}
}
Ptcb->OSTCBDly=0;(8)
Ptcb->OSTCBStat=OS_STAT_RDY;(9)
OSLockNesting++;(10)
OS_EXIT_CRITICAL();(11)
OSDummy();(12)
OS_ENTER_CRITICAL();
OSLockNesting--;(13)
OSTaskDelHook(ptcb);(14)
OSTaskCtr--;
OSTCBPrioTbl[prio]=(OS_TCB*)0;(15)
if(ptcb->OSTCBPrev==(OS_TCB*)0){(16)
ptcb->OSTCBNext->OSTCBPrev=(OS_TCB*)0;
OSTCBList=ptcb->OSTCBNext;
}else{
ptcb->OSTCBPrev->OSTCBNext=ptcb->OSTCBNext;
ptcb->OSTCBNext->OSTCBPrev=ptcb->OSTCBPrev;
}
ptcb->OSTCBNext=OSTCBFreeList;(17)
OSTCBFreeList=ptcb;
OS_EXIT_CRITICAL();
OSSched();(18)
return(OS_NO_ERR);
}else{
OS_EXIT_CRITICAL();
return(OS_TASK_DEL_ERR);
}
}
一旦所有条件都满足了,OS_TCB就会从所有可能的μC/OS-Ⅱ的数据结构中移除。OSTaskDel()分两步完成该移除任务以减少中断响应时间。首先,如果任务处于就绪表中,它会直接被移除[L4.11(6)]。如果任务处于邮箱、消息队列或信号量的等待表中,它就从自己所处的表中被移除[L4.11(7)]。接着,OSTaskDel()将任务的时钟延迟数清零,以确保自己重新允许中断的时候,ISR例程不会使该任务就绪[L4.11(8)]。最后,OSTaskDel()置任务的.OSTCBStat标志为OS_STAT_RDY。注意,OSTaskDel()并不是试图使任务处于就绪状态,而是阻止其它任务或ISR例程让该任务重新开始执行(即避免其它任务或ISR调用OSTaskResume()[L4.11(9)])。这种情况是有可能发生的,因为OSTaskDel()会重新打开中断,而ISR可以让更高优先级的任务处于就绪状态,这就可能会使用户想删除的任务重新开始执行。如果不想置任务的.OSTCBStat标志为OS_STAT_RDY,就只能清除OS_STAT_SUSPEND位了(这样代码可能显得更清楚,更容易理解一些),但这样会使得处理时间稍长一些。
要被删除的任务不会被其它的任务或ISR置于就绪状态, 因为该任务已从就绪任务表中删除了,它不是在等待事件的发生,也不是在等待延时期满,不能重新被执行。为了达到删除任务的目的,任务被置于休眠状态。正因为这样,OSTaskDel()必须得阻止任务调度程序[L4.11(10)]在删除过程中切换到其它的任务中去,因为如果当前的任务正在被删除,它不可能被再次调度!接下来,OSTaskDel()重新允许中断以减少中断的响应时间[L4.11(11)]。
评论