uc/os任务管理

//ucos的初始化
void OSInit(void)
{
#if OS_VERSION>=204
OSInitHookBegin();
#endif
OS_InitMisc(); //初始化系统需要的一些变量
OS_InitRdyList(); //初始化就绪列表
OS_InitTCBList(); //初始化TCB列表
OS_InitEventList(); //初始化事件列表
#if (OS_VERSION>=251)&&(OS_FLAG_EN>0)&&(OS_MAX_FLAGS>0)
OS_FlagInit(); //初始化事件标志
#endif
#if (OS_MEM_EN>0)&&(OS_MAX_MEM_PART>0)
OS_MemInit(); //初始化内存管理
#endif
#if (OS_Q_EN>0)&&(OS_MAX_QS>0)
QS_Init(); //初始化消息队列
#endif
OS_InitTaskIdle(); //建立空闲任务
#if OS_TASK_STAT_EN>0
OS_InitTaskStat(); //建立统计任务
#endif
#if OS_VERSION>=204
OSInitHookEnd();
#endif
}



/*uc/os-II的任务控制块的数据结构的定义*/
typedef struct os_tcb{
OS_STK *OSTCBStKPtr; /*指向任务独立堆栈的栈顶指针*/
#if OS_TASK_CREATE_EXT_EN
void *OSTCBExtPtr; /*指向用户定义的任务控制块拓展*/
OS_STK *OSTCBStkBottom; /*指向任务栈区栈底的指针*/
INT32U OSTCBStkSize; /*栈区中可容纳的存储单元个数*/
INT16U OSTCBopt; /*创建TCB的类型选择*/
INT16U OSTCBId; /*任务识别号*/
#endif
struct os_tcb *OSTCBNEXT; /*指向OS_TCB联表中下一个元素*/
struct os_tcb *OSTCBPre; /*指向OS_TCB联表中前面一个元素*/
#if(OS_Q_EN&&(OS_MAX_QS>=2))||OS_MBOX_EN||OS_SEM_EN
OS_EVENT *OSTCBEvent; /*指向事件控制块的的指针*/
#endif
#if(os_Q_EN&&(OS_MAX_QS>=2))||OS_MBOX_EN
void *OSTCBMsg; /*指向传给任务的消息指针*/
#endif
INT16U OSTCBDly; /*任务允许等待事件发生的最多时钟节拍数*/
INT8U OSTCBStat; /*任务的状态字*/
INT8U OSTCBPrio; /*任务的优先级*/
INT8U OSTCBX; /*任务就绪表位图矩阵的X坐标*/
INT8U OSTCBY; /*任务就绪表位图矩阵的Y坐标*/
INT8U OSTCBBitX; /*任务就绪表位图矩阵的X坐标操作掩码*/
INT8U OSTCBbitY; /*任务就绪表位图矩阵的Y坐标操作掩码*/
#if OS_TASK_DEL_EN
BOOLEAN OSTCBDelReg; /*表示该任务是否删除*/
#endif
}OS_TCB;



/*基本型任务创建函数的原型声明*/
INT8U OSTaskCreate(void(*task)(void *pd),void *pdata,OS_STK *ptos,INT8U prio)
/*拓展型任务创建函数声明*/
INT8U OSTaskCreateExt(
void (*task)(void *pd), //指向任务的执行函数的指针
void *pdata, //指向任务执行的参数指针
OS_STK *ptos, //指向任务自用栈栈顶的指针
INT8U prio; //任务的优先级
INT16U id, //任务的标识符
OS_STK *pbos, //指向任务自用栈栈底的指针
INT32U stk_size, //任务自用栈的空间大小
void *pext, //指向任务扩展指针
INT16U opt) //任务的选项



//任务的建立
INT8U OSTaskCreate(void (*task)(void *pd),void *pdata,OS_STK *ptos,INT8U prio)_
{
void *psp;
INT8U err;

if(prio>OS_LOWEST_PRIO) //确定用户输入的优先级是否在有效的范围内
{
return (OS_PRIO_INVALID);
}

OS_ENTER_CRITICAL(); //进入临界区
if(OSTCBPrioTbl[prio]==(OS_TCB*)0) //确定优先级没有被其他任务占用
{
OSTCBPrioTbl[prio]==(OS_TCB*)1; //如果分配的优先级空闲,保留该优先级
OS_EXIT_CRITICAL(); //退出临界区


psp=(void *)OSTaskStkInit(task,pdata,ptos,0); //初始化任务堆栈
err=OSTCBInit(prio,psp,(void*)0,0,0,(void*)0,0); //从空闲的OS_TCB池获得并初始化一个任务控制块OS_TCB

if(err==OS_NO_ERR)
{//从OS_TCBInit()返回后,会检测返回的代码,如果成功,给OSTaskCtr加1
OS_ENTER_CRITICAL();
OSTaskCtr++;
OSTaskCreateHook(OSTCBPrioTbl[prio]); //是用户自己定义的函数,用来拓展OSTaskCreate()的功能
OS_EXIT_CRITICAL();

if(OSRunning) //如果多任务环境已经启动,立即执行任务调度
{
OSSched();
}
}
else
{//从OS_TCBInit()返回后,会检测返回的代码,如果失败,放弃该优先级
OS_ENTER_CRITICAL();
OSTCBPrioTbl[prio]=(OS_TCB*)0;
OS_EXIT_CRITICAL();
}
return (err);
}
else
{
OS_EXIT_CRITICAL();
return (OS_PRIO_EXIST);
}
}

//获取一块空闲的TCB
INT8U OS_TCBInit(INT8U prio,OS_STK *ptos,
OS_STK *pbos,
INT16U id,
INT32U stk_size,
void *pnext,
INT16U opt)
{
#if OS_CRITICAL_METHOD==3
OS_CPU_SR cpu_sr;
#endif
OS_TCB *ptcb;

OS_ENTER_CRITICAL();
ptcb=OSTCBFreeList; //试图从OS_TCB缓冲池中获取一个任务控制块OS_TCB
if(ptcb!=(OS_TCB *)0)
{
OSTCBFreeList=ptcb->OSTCBNext;
OS_EXIT_CRITICAL();
ptcb->OSTCBStkPtr=ptos; //如果OS_TCB池中有空闲的OS_TCB,就被初始化
ptcb->OSTCBPrio=(INT8U)prio;
ptcb->OSTCBStat=OS_STAT_RDY;
ptcb->OSTCBDly=0;

#if OS_TASK_CREATE_EXT_EN>0
//如果允许OSTaskCreateExt()的代码生成,额外的变OS_TCB
ptcb->OSTCBExtPtr=pnext;
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=prio>>3; //为了节省任务调度时间,对一些参数提前运算
ptcb->OSTCBBitY=OSMapTbl[ptcb->OSTCBY];
ptcb->OSTCBX=prio&0x07;
ptcb->OSTCBBitX=OSMapTbl[ptcb->OSTCBX];

#if OS_EVENT_EN>0
ptcb->OSTCBEventPtr=(OS_EVENT *)0;
#endif
#if (OS_VERSION>=251)&&(OS_FLAG_EN>0)&&(OS_MAX_FLAGS>0)&&(OS_TASK_DEL_EN>0)
//如果事件标志的使用得到允许,则指向事件标志节点的指针被初始化为空指针
ptcb->OSTCBFlagNode=(OS_FLAG_NODE *)0;
#endif
#if
(OS_MBOX_EN>0)||((OS_Q_EN>0)&&(OS_MAX_QS>0))
ptcb->OSTCBMsg=(void*)0;
#endif
#if OS_VERISON>=204
OSTCBInitHook(ptcb);
#endif
OSTaskCreateHook(ptcb);
OS_ENTER_CRITICAL();
//需要将OS_TCB插入到已建立任务的OS_TCB的双向联表中
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;
}
OS_EXIT_CRITICAL();
return (OS_NO_MORE_TCB);
}



//uc/OS-II C 语言任务调度函数
void OS_Shedul(void)
{
#if OS_CRITICIAL_METHOD==3
OS_CPU_SR cpu_sr; /*为CPU的状态寄存器分配存储器*/
#endif
INT8U y;
OS_ENTER_CRITICAL();
if((OSIntNesting==0)&&(OSLockNecting==0))
{
/*任务调度的要求:所有的ISR执行完毕并且任务调度未加锁*/
y=OSUnMapTabl[OSRbyGrp];/*得到最高就绪任务所在任务的分组组号*/
OSPrioHighRby=(INT8U)((y<<3)+OSUnMapTbl[OSRbyTbl[y]];/*得到最高就绪任务的优先级*/
if(OSPrioHighBy!=OSPrioCur)/*如果当前任务优先级就是最高优先级的任务,则不进行调度*/
{
OSTCBHighBy=OSTCBPrioTbl[OSPrioHighRby];/*获得最高优先级就绪的TCB指针*/
OSCtxSwCtr++;/*任务切换计数器增1*/
OS_TASk_SW();/*执行任务级任务切换*/
}
}
OS_EXIT_CRITICAL();
}



//堆栈的检测,OS_STK_DATA是一个结构,记录已用的堆栈空间和剩余的堆栈空间
INT8U OSTaskStkChk(INT8U prio,OS_STK_DATA *pdata)
{
OS_TCB *ptcb;
OS_STK *pchk;
NT32U free;
INT32U size;
pdata->OSFree=0;
pdata->OSUsed=0;
if(prio>OS_LOWEST_PRIO&&prio!=OS_PRIO_SELF)
{
return (OS_PRIO_INVALID);
}
OS_ENTER_CRITICAL();
if(prio==OS_PRIO_SELF) //优先级等于当前的任务优先级
{
prio=OSTCBCur->OSTCBPrio;
}
ptcb=OSTCBPrioTbl[prio];
if(ptcb==(OS_TCB)*0) //任务不存在
{
OS_EXIT_CRITICAL();
return (OS_TASK_NOT_EXIST);
}
if((ptcb->OSTCBOpt&OS_TASK_OPT_STK_CHK)==0)
{
OS_EXIT_CRITICAL();
return (OS_TASK_OPT_ERR);
}
free=0;

size=ptcb->OSTCBStkSize;
pchk=ptcb->OSTCBStkBottom;

OS_EXIT_CRITICAL();
#if OS_TASK_GROWTH==1 //如果堆栈是增长型,从低地址往高地址放
while(*pchk++==0)
{
free++;
}
#else
while(*pchk--==0)
{
free++;
}
#endif
pdata->OSFree=free*sizeof(OS_STK);
pdata->OSUsed=(size-free)*sizeof(OS_STK);
return (OS_NO_ERR);
}



//改变任务的优先级
INT8U OSTaskChangePrio(INT8U oldprio,INT8U newprio)
{
#if OS_EVENT_EN
OS_EVENT *prevent;
#endif
OS_TCB *ptcb;
INT8U x;
INT8U y;
#if OS_LOWEST_PRIO<=63
INT8U bitx;
INT8U bity;
#else
INT16U bitx;
INT16U bity;
#endif
INT8U y_old;
#if OS_CRITICAL_METHOD==3
OS_CPU_SR cpu_sr=0;
#endif


#if OS_ARG_CHK_EN>0
if(oldprio>=OS_LOWEST_PRIO) //不能改变空闲任务的优先级,但可以改变调用本任务或者其他任务的优先级
{
if(oldprio!=OS_PRIO_SELF)
{
return (OS_PRIO_INVALID);
}
}
if(newprio>=OS_LOWEST_PRIO)
{
return (OS_PRIO_INVALID);
}
#endif

OS_ENTER_CRITICAL();
if(OSTCBPrioTbl[newprio]!=(OS_TCB *)0)
{//ucOS-II不允许多个任务具有相同的优先级
OS_EXIT_CRITICAL();
return (OS_PRIO_EXIST);
}
if(oldprio==OS_PRIO_SELF)
{
//检测目前的任务是否想改变它的优先级
oldprio=OSTCBCur->OSTCBPrio;
}
ptcb=OSTCBPrioTbl[oldprio];

if(ptcb==(OS_TCB*)0)
{//如果想要改变优先级的任务不存在
OS_EXIT_CRITICAL();
return (OS_TASK_NOT_EXIST);
}

#if OS_LOWEST_PRIO<=63 //计算新优先级任务的OS_TCB中的某些值
y=(INT8U)(newprio>>3);
x=(INT8u)(newprio&ox07);
bity=(INT8U)(1<<y);
bitx=(INT8U)(1<<x);

#else
y=(INT8U)((newprio>>4)&oxFF);
x=(INT8U)((newprio&0x0f);
bity=(INT16U)(1<<y);
bitx=(INT16U)(1<<x);
#endif

OSTCBPrioTbl[oldprio]=(OS_TCB *)0;//插入NULL指针将指向当前OS_TCB的指针从优先级表中删除
OSTCBPrioTbl[newprio]=ptcb; //将指向任务OS_TCB的指针存到OSTCBPrioTbl[]中·
y_old=ptcb->OSTCBY;
if((OSRdyTbl[y_old]&ptcb->OSTCBBitX)!=0) //改变优先级是否就绪
{
OSRdyTbl[y_old]&=~ptcb->OSTCBBitX;
if(OSRdyTbl[y_old]==0)
{
OSRdyGrp&=~ptcb->OSTCBBitY;
}
//如果该任务处于就绪状态,它必须在当前的优先级下从就绪表总移除,然后在新的优先级下插入到就绪表中
OSRdyGrp|=bity;
OSRdyTbl[y]|=bitx;

#if OS_EVENT_EN
}else
{
pevent=ptcb->OSTCBEventPtr;
if(prevent!=(OS_EVENT*)0)
{//如果任务为就绪,任务正在等待信号量,邮件或者是消息队列
prevent->OSEventTbl[y_old]&=~ptcb->OSTCBBitX;
if(prevent->OSEventTbl[y_old]==0)
{
prevent->OSEventGrp&=~ptcb->OSTCBitY;
}
//如果任务在等待某一事件发生,OSTaskChangePrio()必须将任务从事件控制块的等待队列(在以前的优先级下)中移除,
//并在新的优先级下将事件插入到等待队列中
pevent->OSEventGrp|=bity;
prevent->OSEventTbl[y]=bitx;
}
#endif
}
ptcb->OSTCBPrio=newprio;
ptcb->OSTCBY=y;
ptcb->OSTCBX=x;
ptcb->OSTCBBitY=bity;
ptcb->OSTCBBitX=bitx;
OS_EXIT_CRITICAL();
OS_Sched(); //任务调度程序被调用
return (OS_NO_ERR);
}

//删除任务
INT8U OSTaskDel(INT8U prio)
{
#if OS_CRITICAL_METHOD==3
OS_CPU_SR cpu_sr;
#endif

#if OS_EVENT_EN>0
OS_EVENT *prevent;
#endif
#if (OS_VERSION>=251)&&(OS_FLAG_EN>0)&&(OS_MAX_FLAGS>0)
OS_FLAG_NODE *pnode;
#endif
OS_TCB *ptcb;
BOOLEAN self;

if(OSIntNesting>0) // 确保不是在中断服务子程序中调用
{
return (OS_TASK_DEL_ISR);
}
#if OS_ARG_CHK_EN>0
if(prio==OS_IDLE_PRIO) //确保删除的不是空闲任务
{
return (OS_TASK_DEL_IDLE);
}
if(prio>=OS_LOWEST_PRIO&&prio!=OS_PRIO_SELF)
{
return (OS_PRIO_INVALID);
}
#endif
OS_ENTER_CRITICAL();
if(prio==OS_PRIO_SELF) //可以通过OS_PRIO_SELF参数来删除自己
{
prio=OSTCBCur->OSTCBPrio;
}
ptcb=OSTCBPrioTbl[prio];
if(ptcb!=(OS_TCB *)0) //应确保任务是存在的
{
if((OSRdyTbl[ptcb->OSTCBY]&=~ptcb->OSTCBBitX)==0x00)
{
OSRdyGrp&=~ptcb->OSTCBBitY;
}

#if OS_EVENT_EN>0
prevent=ptcb->OSTCBEventPtr;
if(prevent!=(OS_EVENT *)0) //如果任务处于不兼容信号量,邮箱,消息队列或信号量的等待表中,从所在表中删除
{
if((pevent->OSEventTbl[ptcb->OSTCBY]&=~ptcb->OSTCBBitX)==0)
OSRdyGrp&=~ptcb->OSTCBBitY;
}
}
#endif
#if (OS_VERSION>=251)&&(OS_FLAG_EN>0)&&(OS_MAX_FLAGS>0) //如果处于事件标志的等待表中,从此表删除
pnode=ptcb->OSTCBFlagNode;
if(pnode!=(OS_FLAG_NODE*)0)
{
OS_FlagUnlink(pnode);
}
#endif
ptcb->OSTCBDly=0; //任务时钟节拍延迟数清零,
ptcb->OSTCBStat=OS_STAT_RDY; //置任务的OSTCBStatOSSSTATRDY
if(OSLockNesting<255)
{
OSLockNesting++;
}
OS_EXIT_CRITICAL();
OS_Dummy(); //确保处理器在中断允许的情况下至少执行一个指令
OS_ENTER_CRITICAL();
if(OSLockNesting>0)
{
OSLockNesting--; //锁定嵌套计数器(OSLockNesting减1以重新允许任务调度
}
OSTaskDelHook(ptcb);
OSTaskCtr--; //任务计数减—
OSTCBPrioTbl[prio]=(OS_TCB *)0; //将指向被删除的任务的OS_TCB的指针指向NULL
if(ptcb->OSTCBPrev==(OS_TCB *)0) //将被删除的任务OS_TCB双联表中移除
{
ptcb->OSTCBNext->OSTCBPrev=(OS_TCB *)0;
OSTCBList=ptcb->OSTCBNext;
}
else
{
ptcb->OSTCBPrev->OSTCBNext=ptcb->OSTCBNext;
ptcb->OSTCBNext->OSTCBPrev=ptcb->OSTCBPrev;
}

ptcb->OSTCBNext=OSTCBFreeList; //OS_TCB返OS_TCB表中,并允许其他任务的建立
OSTCBFreeList=ptcb;
OS_EXIT_CRITICAL();
OS_Sched(); //调用任务调度程序
return (OS_NO_ERR);
}
OS_EXIT_CRITICAL();
return (OS_TASK_DEL_ERR);
}


//请求删除任务
INT8U OSTaskDelReq(INT8U prio)
{
#if OS_CRITICAL_METHOD==3
OS_CPU_SR cpu_sr;
#endif
BOOLEAN stat;
INT8U err;
OS_TCB *ptcb;
#if OS_ARG_CHK_EN>0
if(prio==OS_IDLE_PRIO) //如果需要被删除的任务是空闲任务,报错
{
return (OS_TASK_DEL_IDLE);
}
if(prio>=OS_LOWEST_PRIO&&prio!=OS_PRIO_SELF) //必须保证请求删除的优先级有效
{
return (OS_PRIO_INVALID);
}
#endif
if(prio==OS_PRIO_SELF) //如果删除自身,存储在OS_TCB中的标志将返回
{
OS_ENTER_CRITICAL();
stat=OSTCBCur->OSTCBDelReq;
OS_EXIT_CRITICAL();
return (stat);
}
ptcb=OSTCBPrioTbl[prio];
if(ptcb!=(OS_TCB*)0)
{
ptcb->OSTCBDelReq=OS_TASK_DEL_REQ;
err=OS_NO_ERR;
}
else
{
err=OS_TASK_NOT_EXIST; //如果任务不存在,返回错误信息
}
OS_EXIT_CRITICAL();
return (err);
}

//请求删除其他任务的任务
void RequestorTask(void *pdata)
{
INT8U err;
pdata=pdata;
for(;;)
{
if(TaskToBeDeleted())//需要被删除
{
while(OSTaskDelReq(TASK_TO_DEL_PRIO)!=OS_TASK_NOT_EXIST)
{
OSTimeDly(1);
}
}
}
}

//需要删除自己的任务
void TaskToBeDeleted(void *pdata)
{
INT8U err;
pdata=pdata;
for(;;)
{ //应用程序代码
if(OSTaskDelReq(OS_PRIO_SELF)==OS_TASK_DEL_REQ)
{
//释放所有的占用资源
//释放所有动态内存
OSTaskDel(OS_PRIO_SELF);
}
else
{
//应用程序代码
}
}
}
Live together,or Die alone!
原文地址:https://www.cnblogs.com/hzhida/p/2395669.html