ucos官网中在那个文件中改时钟节拍啊,

ucos II 内核学习之五:时钟节拍
ucos II 内核学习之五:时钟节拍
& &&http://blog.csdn.net/h32dong809/article/details/70825132011&&&&&&&&&&&&&&&& ucos II 内核学习之二 :时钟节拍
ucos II 里,时钟节拍就好比是人的心脏一样重要,。它对于CPU能顺利在各任务间切换有着至关重要的作用。
Ucos II 需要用户提供时钟源,在muc21项目了,我使用了定时器0作为时钟源。使用时钟源有一个特别需要注意的地方:用户必须在多任务系统启动以后再开启时钟节拍器,也就是在调用OSStart()之后。
Ucos II中的时钟节拍服务是通过在定时器中断服务子程序中调用OSTimeTick()实现的。
OSTimeTick()代码如下:
void OSTimeTick (void)
&&& OS_TCB *
&&& OSTimeTickHook();&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& (1)
&&& ptcb = OSTCBL&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& (2)
&&& while (ptcb-&OSTCBPrio != OS_IDLE_PRIO) { &&&&&&&& &&&&&&&&&&&&&&&&&&&&(3)
&&&&&&& OS_ENTER_CRITICAL();
&&&&&&& if (ptcb-&OSTCBDly != 0) {
&&&&&&&&&&& if (--ptcb-&OSTCBDly == 0) {
&&&&&&&&&&&&&&& if (!(ptcb-&OSTCBStat & OS_STAT_SUSPEND)) {&&&&&&& &&&&&& (4)
&&&&&&&&&&&&&&&&&&& OSRdyGrp&&&&&&&&&&&&&& |= ptcb-&OSTCBBitY;&&&&&&&&&& &&& (5)
&&&&&&&&&&&&&&&&&&& OSRdyTbl[ptcb-&OSTCBY] |= ptcb-&OSTCBBitX;
&&&&&&&&&&&&&&& } else {
&&&&&&&&&&&&&&&&&&& ptcb-&OSTCBDly = 1;
&&&&&&&&&&&&&&& }
&&&&&&&&&&& }
&&&&&&& Ptcb = ptcb-&OSTCBN
&&&&&&& OS_EXIT_CRITICAL();
&&& OS_ENTER_CRITICAL();&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& (6)
&&& OSTime++;&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& (7)
&&& OS_EXIT_CRITICAL();
我们知道,CPU总是执行就绪表中优先级最高的任务,任务有没有在就绪表中就得依靠OSTimeTick()了。OSTimeTick()很大的工作是给每个用户任务控制块OS_TCB中的时间延时项OSTCBDly减1,当某任务的任务控制块中的时间延时项OSTCBDly减到了零,这个任务就进入了就绪态。
下面是对以上代码的分析。
OSTimtick()先调用可由用户定义的时钟节拍外连函数OSTimeTickHook(),这个外连函数可以将时钟节拍函数OSTimetick()予以扩展[L3.2(1)]。Ucos II的作者决定首先调用OSTimTickHook()是打算在时钟节拍中断服务一开始就给用户一个可以做点儿什么的机会,因为用户可能会有一些时间要求苛刻的工作要做。OSTimtick()中量大的工作是给每个用户任务控制块OS_TCB中的时间延时项OSTCBDly减1(如果该项不为零的话)。OSTimTick()从OSTCBList开始,沿着OS_TCB链表做,一直做到空闲任务[L3.21(3)]。当某任务的任务控制块中的时间延时项OSTCBDly减到了零,这个任务就进入了就绪态[L3.21(5)]。而确切被任务挂起的函数OSTaskSuspend()挂起的任务则不会进入就绪态[L3.21(4)]。OSTimTick()的执行时间直接与应用程序中建立了多少个任务成正比。OSTimeTick()还通过调用OSTime[L3.21(7)]累加从开机以来的时间,用的是一个无符号32位变量。注意,在给OSTime加1之前使用了关中断,因为多数微处理器给32位数加1的操作都得使用多条指令。
发表评论:
TA的最新馆藏ucos-iii时钟节拍
这回说下系统中很重要的时钟节拍
在系统初始化的时候就用下面这个函数建了一个时钟任务。
/************************************************************************************************************************
void &OS_TickTaskInit (OS_ERR &*p_err)
#ifdef OS_SAFETY_CRITICAL
& & if (p_err == (OS_ERR *)0) {
& & & & OS_SAFETY_CRITICAL_EXCEPTION();
& & OSTickCtr & & & & = (OS_TICK)0u; & & & & & & & & & & & &/* Clear the tick counter & & & & & & & & & & & & & & & & */
& & OSTickTaskTimeMax = (CPU_TS)0u;
& & OS_TickListInit(); & & & & & & & & & & & & & & & & & & &/* 初始化一下时钟列表,一般延时的任务就在这里管理,下面看下它的内容*/
& & & & & & & & & & & & & & & & & & & & & & & & & & & & & & /* ---------------- CREATE THE TICK TASK ---------------- */
& & if (OSCfg_TickTaskPrio &= (OS_CFG_PRIO_MAX - 1u)) { & & /* Only one task at the 'Idle Task' priority & & & & & & &*/
& & & & *p_err = OS_ERR_PRIO_INVALID;
/*下面是建时钟节拍任务*/
& & OSTaskCreate((OS_TCB & & *)&OSTickTaskTCB,
& & & & & & & & &(CPU_CHAR & *)((void *)&uC/OS-III Tick Task&),
& & & & & & & & &(OS_TASK_PTR )OS_TickTask,
& & & & & & & & &(void & & & *)0,
& & & & & & & & &(OS_PRIO & & )OSCfg_TickTaskPrio,
& & & & & & & & &(CPU_STK & &*)OSCfg_TickTaskStkBasePtr,
& & & & & & & & &(CPU_STK_SIZE)OSCfg_TickTaskStkLimit,
& & & & & & & & &(CPU_STK_SIZE)OSCfg_TickTaskStkSize,
& & & & & & & & &(OS_MSG_QTY &)0u,
& & & & & & & & &(OS_TICK & & )0u,
& & & & & & & & &(void & & & *)0,
& & & & & & & & &(OS_OPT & & &)(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
& & & & & & & & &(OS_ERR & & *)p_err);
void &OS_TickListInit (void)
& & OS_TICK_SPOKE_IX &
& & OS_TICK_SPOKE & & *p_
/*如果一个任务休息了,那它会从就绪列中退出,然后用OS_TICK_SPOKE来管理*/
& & for (i = 0u; i & OSCfg_TickWheelS i++) {
& & & & p_spoke & & & & & & & &= (OS_TICK_SPOKE *)&OSCfg_TickWheel[i];/*OSCfg_TickWheel[]在这我也不知道怎么说,先放下,往下看,会说的*/
& & & & p_spoke-&FirstPtr & & &= (OS_TCB & & & &*)0;
& & & & p_spoke-&NbrEntries & &= (OS_OBJ_QTY & & )0u;
& & & & p_spoke-&NbrEntriesMax = (OS_OBJ_QTY & & )0u;
这时我也要说下OS_TICK_SPOKE结构体
struct &os_tick_spoke {
& & OS_TCB & & & & & & &*FirstP & & & & & & & & & & & & &/* 这里怎么说呢比如挂OSCfg_TickWheel[1]任务可能有很多,但这里的
FirstPtr只指第一个任务,其他任务是用任务控制块中的成员TickNextPtr,TickPrevPtr来连接的*/
& & OS_OBJ_QTY & & & & & NbrE & & & & & & & & & & & &/* 还是用OSCfg_TickWheel[1]举例,挂要这个spoke上的任务数 & & & & & &*/
& & OS_OBJ_QTY & & & & & NbrEntriesM & & & & & & & & & & /* 这上的最多可以是多少个任务,(这说的不一定对) & & & & & & & */
OSCfg_TickWheel对于这个大家先别急,等我说到OSTimeDly说,这节会说的。
*************************************************************************************************************************/
/************************************************************************************************************************
这个任务是在上面的函数中建立的。
void &OS_TickTask (void *p_arg)
& & OS_ERR &
& & CPU_TS &
& & p_arg = p_ & & & & & & & & & & & & & & & & & & & & &/* Prevent compiler warning & & & & & & & & & & & & & & & */
& & while (DEF_ON) {
& & & & (void)OSTaskSemPend((OS_TICK &)0,/*这里是要等一个信号量,如果有的话就可以往下干活了,不然就会等这个信号,直到得到这个信号,这个我不会在这说,说到信号量时说*/
& & & & & & & & & & & & & & (OS_OPT & )OS_OPT_PEND_BLOCKING,
& & & & & & & & & & & & & & (CPU_TS &*)&ts,
& & & & & & & & & & & & & & (OS_ERR &*)&err); & & & & & & & /* Wait for signal from tick interrupt & & & & & & & & & &*/
& & & & if (err == OS_ERR_NONE) {
& & & & & & if (OSRunning == OS_STATE_OS_RUNNING) {
& & & & & & & & OS_TickListUpdate(); & & & & & & & & & & & &/* Update all tasks waiting for time & & & & & & & & & & &*/
& & & & & & }
OSTimeTick这个是在定时中断中被调用的,用来给上面这个任务发送信号
我们要自写出一个定时中断,大概1秒进入定时中断几次是由我们定的,同时设置OSCfg_TickRate_Hz,也就是说,1秒,我们会给OS_TickTask
发送OSCfg_TickRate_Hz次信号。也说明这个任务1秒可以调用OS_TickListUpdate多少次。
我们不太会说,总之以上就是我想说的关于时钟节拍。
void &OSTimeTick (void)/*在中断中调用*/
& & OS_ERR &
#if OS_CFG_ISR_POST_DEFERRED_EN & 0u
& & CPU_TS &
& & OSTimeTickHook(); & & & & & & & & & & & & & & & & & & & /* Call user definable hook & & & & & & & & & & & & & & & */
#if OS_CFG_ISR_POST_DEFERRED_EN & 0u
& & ts = OS_TS_GET(); & & & & & & & & & & & & & & & & & & & /* Get timestamp & & & & & & & & & & & & & & & & & & & & &*/
& & OS_IntQPost((OS_OBJ_TYPE) OS_OBJ_TYPE_TICK, & & & & & & /* 如果是到这的话,说明不立刻发送信号 & & & & & & & & & & */
& & & & & & & & (void & & &*)&OSRdyList[OSPrioCur],
& & & & & & & & (void & & &*) 0,
& & & & & & & & (OS_MSG_SIZE) 0u,
& & & & & & & & (OS_FLAGS & ) 0u,
& & & & & & & & (OS_OPT & & ) 0u,
& & & & & & & & (CPU_TS & & ) ts,
& & & & & & & & (OS_ERR & &*)&err);
& &(void)OSTaskSemPost((OS_TCB *)&OSTickTaskTCB, & & & & & &/* Signal tick task & & & & & & & & & & & & & & & & & & & */
& & & & & & & & & & & &(OS_OPT &) OS_OPT_POST_NONE,
& & & & & & & & & & & &(OS_ERR *)&err);
#if OS_CFG_SCHED_ROUND_ROBIN_EN & 0u
& & OS_SchedRoundRobin(&OSRdyList[OSPrioCur]);
#if OS_CFG_TMR_EN & 0u
& & OSTmrUpdateCtr--;/*这是用于软定时器的先不说了*/
& & if (OSTmrUpdateCtr == (OS_CTR)0u) {
& & & & OSTmrUpdateCtr = OSTmrUpdateC
& & & & OSTaskSemPost((OS_TCB *)&OSTmrTaskTCB, & & & & & & &/* Signal timer task & & & & & & & & & & & & & & & & & & &*/
& & & & & & & & & & & (OS_OPT &) OS_OPT_POST_NONE,
& & & & & & & & & & & (OS_ERR *)&err);
*************************************************************************************************************************/
/************************************************************************************************************************
好了说下任务的延时OSTimeDly,我们看这个函数的入口参数就知道,一个任务只能延时自己。
void &OSTimeDly (OS_TICK & dly,
& & & & & & & & &OS_OPT & &opt,
& & & & & & & & &OS_ERR & *p_err)
& & CPU_SR_ALLOC();
#ifdef OS_SAFETY_CRITICAL
& & if (p_err == (OS_ERR *)0) {
& & & & OS_SAFETY_CRITICAL_EXCEPTION();
#if OS_CFG_CALLED_FROM_ISR_CHK_EN & 0u
& & if (OSIntNestingCtr & (OS_NESTING_CTR)0u) { & & & & & & /* Not allowed to call from an ISR & & & & & & & & & & & &*/
& & & &*p_err = OS_ERR_TIME_DLY_ISR;
& & if (OSSchedLockNestingCtr & (OS_NESTING_CTR)0u) { & & & /* Can't delay when the scheduler is locked & & & & & & & */
& & & &*p_err = OS_ERR_SCHED_LOCKED;
& & switch (opt) {
& & & & case OS_OPT_TIME_DLY:
& & & & case OS_OPT_TIME_TIMEOUT:
& & & & case OS_OPT_TIME_PERIODIC:
& & & & & & &if (dly == (OS_TICK)0u) { & & & & & & & & & & &/* 0 means no delay! & & & & & & & & & & & & & & & & & & &*/
& & & & & & & & *p_err = OS_ERR_TIME_ZERO_DLY;
& & & & & & & & &
& & & & & & &}
& & & & & & &
& & & & case OS_OPT_TIME_MATCH:
& & & & & & &
& & & & default:
& & & & & & *p_err = OS_ERR_OPT_INVALID;
& & & & & & &
& & OS_CRITICAL_ENTER();
& & OSTCBCurPtr-&TaskState = OS_TASK_STATE_DLY;/*当前任务的状态变化*/
& & OS_TickListInsert(OSTCBCurPtr,
& & & & & & & & & & & dly,
& & & & & & & & & & & opt,
& & & & & & & & & & & p_err);
& & if (*p_err != OS_ERR_NONE) {
& & & & &OS_CRITICAL_EXIT_NO_SCHED();
& & OS_RdyListRemove(OSTCBCurPtr); & & & & & & & & & & & & &/* Remove current task from ready list & & & & & & & & & &*/
& & OS_CRITICAL_EXIT_NO_SCHED();
& & OSSched(); & & & & & & & & & & & & & & & & & & & & & & &/* Find next task to run! & & & & & & & & & & & & & & & & */
& &*p_err = OS_ERR_NONE;
OS_TickListInsert把当前任务插入到OSCfg_TickWheel[]中。
OS_TICK=INT32 DEF_OCTET_NBR_BITS=8
#define &OS_TICK_TH_RDY & & & & & & & & & & (OS_TICK)(DEF_BIT_FIELD(((sizeof(OS_TICK) * DEF_OCTET_NBR_BITS) / 2u), \16
& & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & ((sizeof(OS_TICK) * DEF_OCTET_NBR_BITS) / 2u))) 16
& & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & &
DEF_INT_CPU_NBR_BITS=32 & & & & & & & & & & & &
#define &DEF_BIT_FIELD(bit_field, bit_shift) & & & & & & & & & & & & & & & & ((((bit_field) &= DEF_INT_CPU_NBR_BITS) ? (DEF_INT_CPU_U_MAX_VAL) & & \
& & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & &: (DEF_BIT(bit_field) - 1uL)) \
& & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & && (bit_shift))
void &OS_TickListInsert (OS_TCB & *p_tcb,
& & & & & & & & & & & & &OS_TICK & time,
& & & & & & & & & & & & &OS_OPT & &opt,
& & & & & & & & & & & & &OS_ERR & *p_err)
& & OS_TICK & & & & & &tick_
& & OS_TICK & & & & & &tick_
& & OS_TICK_SPOKE & & *p_
& & OS_TCB & & & & & &*p_tcb0;
& & OS_TCB & & & & & &*p_tcb1;
& & OS_TICK_SPOKE_IX &
& & if (opt == OS_OPT_TIME_MATCH) { & & & & & & & & & & & & & & &/* 这个选项是说,让你休息到什么时间点 & & & & & & & &*/
& & & & tick_delta = time - OSTickCtr - 1u;
& & & & if (tick_delta & OS_TICK_TH_RDY) { & & & & & & & & & & & /*这说的是,如果你设定的时间点,比当前的时间点小,说明现在,已经经过了那个时间点
,那么就不延时了,但也不绝对这样,不然咱就是想让它休息一会,它就不休息了怎么办。OS_TICK_TH_RDY是我们设置的,
上面的设置方法是我找到的别人做的,自己理解一下吧。
如果小的不是很多就算了,但要是小的很多就让它休息,因为OSTickCtr溢出之后能很快到达time那就会让
任务休息。根据我上面选的几个数可知OS_TICK_TH_RDY=0xffff0000,如果当前时间是0xffff000f,而
我们设置的时间为0xffff0005,那就不会让任务休息了,但要是0x,这样是会让任务休息的*/
& & & & & & p_tcb-&TickCtrMatch = (OS_TICK & & & &)0u;
& & & & & & p_tcb-&TickRemain & = (OS_TICK & & & &)0u;
& & & & & & p_tcb-&TickSpokePtr = (OS_TICK_SPOKE *)0;
& & & & & &*p_err & & & & & & & = &OS_ERR_TIME_ZERO_DLY; & & & & /* ... do NOT delay. & & & & & & & & & & & & & & & & */
& & & & & &
& & & & p_tcb-&TickCtrMatch =
& & & & p_tcb-&TickRemain & = tick_delta + 1u;
& & } else if (time & (OS_TICK)0u) {
& & & & if (opt == OS_OPT_TIME_PERIODIC) { & & & & & & & & & & & /* OS_OPT_TIME_PERIODIC这说的是给一个固定时间,在这上时间里,你做事后,剩下的时间都让任务休息
比如写了一个任务,这个任务中用了这个函数,选项也是这个,时间设的是10,一开始p_tcb-&TickCtrPrev=0,
那么,这个任务工作到了3时,运行到这个函数,这个函数会让他休息7.这时p_tcb-&TickCtrPrev=10,如果下次
工作到了15,那么只会让任务休息5,这时p_tcb-&TickCtrPrev=20*/
& & & & & & tick_next &= p_tcb-&TickCtrPrev +
& & & & & & tick_delta = tick_next - OSTickCtr - 1u;
& & & & & & if (tick_delta & time) { & & & & & & & & & & & & & & /* If next periodic delay did NOT already occur, ... */
& & & & & & & & p_tcb-&TickCtrMatch = tick_ & & & & & & & & /* ... set &next & & & & & & & & &... */
& & & & & & } else {
& & & & & & & & p_tcb-&TickCtrMatch = OSTickCtr + & & & & &/* ... else reset periodic delay. & & & & & & & & & &*/
& & & & & & }
& & & & & & p_tcb-&TickRemain & = p_tcb-&TickCtrMatch - OSTickC
& & & & & & p_tcb-&TickCtrPrev &= p_tcb-&TickCtrM
& & & & } else { & & & & & & & & & & & & & & & & & & & & & & & & /*OS_OPT_TIME_DLY还有这种,就是让任务休息time时间 & & & & & & & & */
& & & & & & p_tcb-&TickCtrMatch = OSTickCtr +
& & & & & & p_tcb-&TickRemain & =
& & & & /*综上所述,根据我们的选项设置了p_tcb-&TickCtrMatch,任务休息,然后当OSTickCtr到达这个值时,就会再次变成就绪的,p_tcb-&TickRemain是还剩下
& & & & 多长的休息时间。p_tcb-&TickCtrPrev,是要OS_OPT_TIME_PERIODIC这个选项时用的,它和p_tcb-&TickCtrMatch一起控制任务休息时间。p_tcb-&TickCtrPrev是
& & & & 上次休息到的时间,p_tcb-&TickCtrMatch是这次可以休息到的时间,一个任务从p_tcb-&TickCtrPrev开始工作,到一某个时间点休息,休息到p_tcb-&TickCtrMatch。
& & & & 然后p_tcb-&TickCtrMatch会成为下次的工作的时间起点。*/
& & } else { & & & & & & & & & & & & & & & & & & & & & & & & & & /* Z ... & & & & & & & & & & & & & & &*/
& & & & p_tcb-&TickCtrMatch = (OS_TICK & & & &)0u;
& & & & p_tcb-&TickRemain & = (OS_TICK & & & &)0u;
& & & & p_tcb-&TickSpokePtr = (OS_TICK_SPOKE *)0;
& & & &*p_err & & & & & & & = &OS_ERR_TIME_ZERO_DLY; & & & & & & /* ... do NOT delay. & & & & & & & & & & & & & & & & */
/*然后用p_tcb-&TickCtrMatch%OSCfg_TickWheelSize得出一个余数赋给spoke,然后取出OSCfg_TickWheel[spoke]来管理这个任务,
说实话,我觉得这种处理方真的很不错,咱们如果设定OSCfg_TickWheelSize为8,任何一个数去除这个数余只有0,1,2,3,4,5,6,7这几种情况,
然后就也说OSCfg_TickWheel[8]中的一个spoke来管理这个任务,如果有很多任务休息,这些任务可能不在同一个上,当系统查是不是有任务
到时间了,可以就绪了,那么只要查看OSCfg_TickWheel[OSTickCtr%OSCfg_TickWheelSize]就行了,这样就可以少查看几个任务(这你明白为什么了吗?)*/
& & spoke & = (OS_TICK_SPOKE_IX)(p_tcb-&TickCtrMatch % OSCfg_TickWheelSize);
& & p_spoke = &OSCfg_TickWheel[spoke];
& & if (p_spoke-&NbrEntries == (OS_OBJ_QTY)0u) { & & & & & & & & /* 如果是挂在这个spoke上的第一个任务 & & & & & & & & & & & & */
& & & & p_tcb-&TickNextPtr & = (OS_TCB & *)0;
& & & & p_tcb-&TickPrevPtr & = (OS_TCB & *)0;
& & & & p_spoke-&FirstPtr & &= &p_
& & & & p_spoke-&NbrEntries &= (OS_OBJ_QTY)1u;
& & } else {
& & & & p_tcb1 & & = p_spoke-&FirstP & & & & & & & & & & & & &/* 如果不是,就把这个任务插到这个链中, & & & & & &*/
& & & & while (p_tcb1 != (OS_TCB *)0) {
& & & & & & p_tcb1-&TickRemain = p_tcb1-&TickCtrMatch- OSTickC & & & & & &/* 看这几行,我们发现,当前任务要插在,一个合适的位置,也就是当前任务插在那个位置后,
& & & & & &
一定是这个任务前面的任务所需的TickRemain 比它所需的小,而它后面的一定比它大 。这样做的原因是
& & & & & &
当查看这个spoke上哪个任务可以进入就绪状况所用的时间最小(这我想我说的明白吧?) & &*/
& & & & & & & & & & & & & & &&
& & & & & & if (p_tcb-&TickRemain & p_tcb1-&TickRemain) { & & & &/* Do we need to insert AFTER current TCB in list? & */
& & & & & & & & if (p_tcb1-&TickNextPtr != (OS_TCB *)0) { & & & &/* Yes, are we pointing at the last TCB in the list? */
& & & & & & & & & & p_tcb1 & & & & & & & = &p_tcb1-&TickNextP /* No, &Point to next TCB in the list & & & & & & & &*/
& & & & & & & & } else {
& & & & & & & & & & p_tcb-&TickNextPtr & = (OS_TCB *)0;
& & & & & & & & & & p_tcb-&TickPrevPtr & = &p_tcb1;
& & & & & & & & & & p_tcb1-&TickNextPtr &= &p_ & & & & & & & /* Yes, TCB to add is now new last entry in the list */
& & & & & & & & & & p_tcb1 & & & & & & & = (OS_TCB *)0; & & & & &/* Break loop & & & & & & & & & & & & & & & & & & & &*/
& & & & & & & & }
& & & & & & } else { & & & & & & & & & & & & & & & & & & & & & & /* Insert before the current TCB & & & & & & & & & & */
& & & & & & & & if (p_tcb1-&TickPrevPtr == (OS_TCB *)0) { & & & &/* Are we inserting before the first TCB? & & & & & &*/
& & & & & & & & & & p_tcb-&TickPrevPtr & = (OS_TCB *)0;
& & & & & & & & & & p_tcb-&TickNextPtr & = &p_tcb1;
& & & & & & & & & & p_tcb1-&TickPrevPtr &= &p_
& & & & & & & & & & p_spoke-&FirstPtr & &= &p_
& & & & & & & & } else { & & & & & & & & & & & & & & & & & & & & /* Insert in between 2 TCBs already in the list & & &*/
& & & & & & & & & & p_tcb0 & & & & & & & = &p_tcb1-&TickPrevP
& & & & & & & & & & p_tcb-&TickPrevPtr & = &p_tcb0;
& & & & & & & & & & p_tcb-&TickNextPtr & = &p_tcb1;
& & & & & & & & & & p_tcb0-&TickNextPtr &= &p_
& & & & & & & & & & p_tcb1-&TickPrevPtr &= &p_
& & & & & & & & }
& & & & & & & & p_tcb1 = (OS_TCB *)0; & & & & & & & & & & & & & &/* Break loop & & & & & & & & & & & & & & & & & & & &*/
& & & & & & }
& & & & p_spoke-&NbrEntries++;
& & if (p_spoke-&NbrEntriesMax & p_spoke-&NbrEntries) { & & & & &/* Keep track of maximum # of entries in each spoke &*/
& & & & p_spoke-&NbrEntriesMax = p_spoke-&NbrE
& & p_tcb-&TickSpokePtr = p_ & & & & & & & & & & & & & & & /* Link back to tick spoke & & & & & & & & & & & & & */
& &*p_err & & & & & & & = OS_ERR_NONE;
画个图来看一个
+-------------+________
| FirstPtr & &|     |
+-------------+
tcb2 & & & & & & & & tcb2
|NbrEntries=3 |    |----&+-----------+ & & &+-----------+ & & &+-----------+
+-------------+    0 &-----|TickPrevPtr| &-----|TickPrevPtr| &-----|TickPrevPtr|
|NbrEntriesMax|
   +-----------+ & & & +-----------+ & & & +-----------+
+-------------+ & & &
   |TickNextPtr|-----& |TickNextPtr|-----& |TickNextPtr|-----& 0
   +-----------+ & & & +-----------+ & & & +-----------+
*************************************************************************************************************************/
/************************************************************************************************************************
&我们在看一下OS_Ticktask任务做的事OS_TickListUpdate();就是看看当前时间没有没任务延时结束,只看OSCfg_TickWheel[OSTickCtr % OSCfg_TickWheelSize]上的任务,
&而且先看第一个如果第一个延时结束才会向后看,因为后面的延时时间都是大于等于前面的,前面的不就绪,后面的也不可能就绪,这样做就很高效,实时性就好
&void &OS_TickListUpdate (void)
& & CPU_BOOLEAN & & & &
& & OS_TICK_SPOKE & & *p_
& & OS_TCB & & & & & &*p_
& & OS_TCB & & & & & &*p_tcb_
& & OS_TICK_SPOKE_IX &
& & CPU_TS & & & & & & ts_
& & CPU_TS & & & & & & ts_
& & CPU_SR_ALLOC();
& & OS_CRITICAL_ENTER();
& & ts_start = OS_TS_GET();
& & OSTickCtr++; & & & & & & & & & & & & & & & & & & & & & & & & & & & /* 每来一次定时中断这个数就加1 & & & & & */
& & spoke & &= (OS_TICK_SPOKE_IX)(OSTickCtr % OSCfg_TickWheelSize);/*刚刚说了,一次只看一个spoke上的任务。看哪个呢?就由这个余数确定*/
& & p_spoke &= &OSCfg_TickWheel[spoke];
& & p_tcb & &= p_spoke-&FirstP
& & done & & = DEF_FALSE;
& & while (done == DEF_FALSE) {
& & & & if (p_tcb != (OS_TCB *)0) {
& & & & & & p_tcb_next = p_tcb-&TickNextP & & & & & & & & & & & & & /* Point to next TCB to update & & & & & & & & */
& & & & & & switch (p_tcb-&TaskState) {
& & & & & & & & case OS_TASK_STATE_RDY:
& & & & & & & & case OS_TASK_STATE_PEND:
& & & & & & & & case OS_TASK_STATE_SUSPENDED:
& & & & & & & & case OS_TASK_STATE_PEND_SUSPENDED:
& & & & & & & & & & &
& & & & & & & & case OS_TASK_STATE_DLY:
& & & & & & & & & & &p_tcb-&TickRemain = p_tcb-&TickCtrMatch & & & & & /* Compute time remaining of current TCB & & & */
& & & & & & & & & & & & & & & & & & & &- OSTickC
& & & & & & & & & & &if (OSTickCtr == p_tcb-&TickCtrMatch) { & & & & & /* Process each TCB that expires & & & & & & & */
& & & & & & & & & & & & &p_tcb-&TaskState = OS_TASK_STATE_RDY;
& & & & & & & & & & & & &OS_TaskRdy(p_tcb); & & & & & & & & & & & & & &/* Make task ready to run & & & & & & & & & & &*/
& & & & & & & & & & &} else {
& & & & & & & & & & & & &done & & & & & & = DEF_TRUE; & & & & & & & & &/*上面我说过,在一个spoke上的任务,TickRemain小的在前面,
& & & & & & & & & & & & &
如果最前面的任务都没就绪,后面的也不会就绪,所以就不向下看了*/
& & & & & & & & & & &}
& & & & & & & & & & &
& & & & & & & & case OS_TASK_STATE_PEND_TIMEOUT:
& & & & & & & & & & &p_tcb-&TickRemain = p_tcb-&TickCtrMatch & & & & & /* 这个是在等事件时用的,一般我们不会让任务无限等那个事件,有时间限制的,时间到了,也会就绪 & & & */
& & & & & & & & & & & & & & & & & & & &- OSTickC
& & & & & & & & & & &if (OSTickCtr == p_tcb-&TickCtrMatch) { & & & & & /* Process each TCB that expires & & & & & & & */
#if (OS_MSG_EN & 0u)
& & & & & & & & & & & & &p_tcb-&MsgPtr & & = (void & & &*)0;
& & & & & & & & & & & & &p_tcb-&MsgSize & &= (OS_MSG_SIZE)0u;
& & & & & & & & & & & & &p_tcb-&TS & & & & = OS_TS_GET();
& & & & & & & & & & & & &OS_PendListRemove(p_tcb); & & & & & & & & & & /* Remove from wait list & & & & & & & & & & & */
& & & & & & & & & & & & &OS_TaskRdy(p_tcb);
& & & & & & & & & & & & &p_tcb-&TaskState &= OS_TASK_STATE_RDY;
& & & & & & & & & & & & &p_tcb-&PendStatus = OS_STATUS_PEND_TIMEOUT; & /* 这是说明我们没等到我们想要的事件 & & & & & & & & & & */
& & & & & & & & & & & & &p_tcb-&PendOn & & = OS_TASK_PEND_ON_NOTHING; &/* 因为超时也就不等了 & & & & & & & & &*/
& & & & & & & & & & &} else {
& & & & & & & & & & & & &done & & & & & & &= DEF_TRUE; & & & & & & & & /* Don't find a match, we're done! & & & & & & */
& & & & & & & & & & &}
& & & & & & & & & & &
& & & & & & & & case OS_TASK_STATE_DLY_SUSPENDED:/*这个位置我想说的是SUSPENDED,说的是待机状态(我也不知道可不可以这么说就是闲着没事),
& & & & & & & &
以上都是延时结束,就会进入就绪,有了这个状态就是延时结束也不会就绪*/
& & & & & & & & & & &p_tcb-&TickRemain = p_tcb-&TickCtrMatch & & & & & /* Compute time remaining of current TCB & & & */
& & & & & & & & & & & & & & & & & & & &- OSTickC
& & & & & & & & & & &if (OSTickCtr == p_tcb-&TickCtrMatch) { & & & & & /*OSTickCtr等于这个任务的 TickCtrMatch结束延时 & & & & & & & */
& & & & & & & & & & & & &p_tcb-&TaskState &= OS_TASK_STATE_SUSPENDED;
& & & & & & & & & & & & &OS_TickListRemove(p_tcb); & & & & & & & & & & /* 你看,虽然从这个链上拿下来了,但也没调用进入就绪状态那个函数,而且不就绪也不是因为延时或等事件*/
& & & & & & & & & & &} else {
& & & & & & & & & & & & &done & & & & & & &= DEF_TRUE; & & & & & & & & /* 这个地方我不说了,上面说过了 & & & & & */
& & & & & & & & & & &}
& & & & & & & & & & &
& & & & & & & & case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:
& & & & & & & & & & &p_tcb-&TickRemain = p_tcb-&TickCtrMatch & & & & & /* Compute time remaining of current TCB & & & */
& & & & & & & & & & & & & & & & & & & &- OSTickC
& & & & & & & & & & &if (OSTickCtr == p_tcb-&TickCtrMatch) { & & & & & /* Process each TCB that expires & & & & & & & */
#if (OS_MSG_EN & 0u)
& & & & & & & & & & & & &p_tcb-&MsgPtr & & = (void & & &*)0;
& & & & & & & & & & & & &p_tcb-&MsgSize & &= (OS_MSG_SIZE)0u;
& & & & & & & & & & & & &p_tcb-&TS & & & & = OS_TS_GET();
& & & & & & & & & & & & &OS_PendListRemove(p_tcb); & & & & & & & & & & /* Remove from wait list & & & & & & & & & & & */
& & & & & & & & & & & & &OS_TickListRemove(p_tcb); & & & & & & & & & & /* Remove from current wheel spoke & & & & & & */
& & & & & & & & & & & & &p_tcb-&TaskState &= OS_TASK_STATE_SUSPENDED;
& & & & & & & & & & & & &p_tcb-&PendStatus = OS_STATUS_PEND_TIMEOUT; & /*PendStatus就那么几个状态,等到事件了OK, 中止也就是不用这个事件了,删除事件,最后就是这个等待超时了 & & & & & & & & & &*/
& & & & & & & & & & & & &p_tcb-&PendOn & & = OS_TASK_PEND_ON_NOTHING; &/* Indicate no longer pending & & & & & & & & &*/
& & & & & & & & & & &} else {
& & & & & & & & & & & & &done & & & & & & &= DEF_TRUE; & & & & & & & & /* Don't find a match, we're done! & & & & & & */
& & & & & & & & & & &}
& & & & & & & & & & &
& & & & & & & & default:
& & & & & & & & & & &
& & & & & & }
& & & & & & p_tcb = p_tcb_
& & & & } else {
& & & & & & done &= DEF_TRUE;
& & ts_end = OS_TS_GET() - ts_ & & & & & & & & & & & & & & & & & /* 看这个函数执行了多少时间,也是验证实时性的,时间越短越好 & & & & */
& & if (ts_end & OSTickTaskTimeMax) {
& & & & OSTickTaskTimeMax = ts_
& & OS_CRITICAL_EXIT();
*************************************************************************************************************************/
/************************************************************************************************************************
下面的函数是将一个处于delay的任务解除,看下限制条件,我们知道,这个函数只解除处于OS_TASK_STATE_DLY状态
和OS_TASK_STATE_DLY_SUSPENDED的任务,任务处于前面的状态,解除delay同时还会使任务就绪,后者只是解除delay
还有,最后还会执行任务的调度,因为解除delay状态并就绪的任务可能优先级比当前运行的任务高。
void &OSTimeDlyResume (OS_TCB &*p_tcb,
& & & & & & & & & & & &OS_ERR &*p_err)
& & CPU_SR_ALLOC();
#ifdef OS_SAFETY_CRITICAL
& & if (p_err == (OS_ERR *)0) {
& & & & OS_SAFETY_CRITICAL_EXCEPTION();
#if OS_CFG_CALLED_FROM_ISR_CHK_EN & 0u
& & if (OSIntNestingCtr & (OS_NESTING_CTR)0u) { & & & & & & /* Not allowed to call from an ISR & & & & & & & & & & & &*/
& & & & *p_err = OS_ERR_TIME_DLY_RESUME_ISR;
#if OS_CFG_ARG_CHK_EN & 0u
& & if (p_tcb == (OS_TCB *)0) { & & & & & & & & & & & & & & /* Not possible for the running task to be delayed! & & & */
& & & &*p_err = OS_ERR_TASK_NOT_DLY;
& & CPU_CRITICAL_ENTER();
& & switch (p_tcb-&TaskState) {
& & & & case OS_TASK_STATE_RDY: & & & & & & & & & & & & & & /* Cannot Abort delay if task is ready & & & & & & & & & &*/
& & & & & & &CPU_CRITICAL_EXIT();
& & & & & & *p_err = OS_ERR_TASK_NOT_DLY;
& & & & & & &
& & & & case OS_TASK_STATE_DLY:
& & & & & & &OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT();
& & & & & & &p_tcb-&TaskState = OS_TASK_STATE_RDY;
& & & & & & &OS_TickListRemove(p_tcb); & & & & & & & & & & &/* Remove task from tick list & & & & & & & & & & & & & & */
& & & & & & &OS_RdyListInsert(p_tcb); & & & & & & & & & & & /* Add to ready list & & & & & & & & & & & & & & & & & & &*/
& & & & & & &OS_CRITICAL_EXIT_NO_SCHED();
& & & & & & *p_err = OS_ERR_NONE;
& & & & & & &
& & & & case OS_TASK_STATE_PEND:
& & & & & & &CPU_CRITICAL_EXIT();
& & & & & & *p_err = OS_ERR_TASK_NOT_DLY;
& & & & & & &
& & & & case OS_TASK_STATE_PEND_TIMEOUT:
& & & & & & &CPU_CRITICAL_EXIT();
& & & & & & *p_err = OS_ERR_TASK_NOT_DLY;
& & & & & & &
& & & & case OS_TASK_STATE_SUSPENDED:
& & & & & & &CPU_CRITICAL_EXIT();
& & & & & & *p_err = OS_ERR_TASK_NOT_DLY;
& & & & & & &
& & & & case OS_TASK_STATE_DLY_SUSPENDED:
& & & & & & &OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT();
& & & & & & &p_tcb-&TaskState = OS_TASK_STATE_SUSPENDED;
& & & & & & &OS_TickListRemove(p_tcb); & & & & & & & & & & &/* Remove task from tick list & & & & & & & & & & & & & & */
& & & & & & &OS_CRITICAL_EXIT_NO_SCHED();
& & & & & & *p_err & & & & & &= OS_ERR_TASK_SUSPENDED;
& & & & & & &
& & & & case OS_TASK_STATE_PEND_SUSPENDED:
& & & & & & &CPU_CRITICAL_EXIT();
& & & & & & *p_err = OS_ERR_TASK_NOT_DLY;
& & & & & & &
& & & & case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:
& & & & & & &CPU_CRITICAL_EXIT();
& & & & & & *p_err = OS_ERR_TASK_NOT_DLY;
& & & & & & &
& & & & default:
& & & & & & &CPU_CRITICAL_EXIT();
& & & & & & *p_err = OS_ERR_STATE_INVALID;
& & & & & & &
& & OSSched();
*************************************************************************************************************************/
/************************************************************************************************************************
将任务从管理它的spoke上卸下,这个任务不在指向这个spoke,这个spoke也不指向这个任务。这个任务不再指向这个spoke上的其他任务,
这个spoke上的其他任务也不指向它。
void &OS_TickListRemove (OS_TCB &*p_tcb)
& & OS_TICK_SPOKE &*p_
& & OS_TCB & & & & *p_tcb1;
& & OS_TCB & & & & *p_tcb2;
& & p_spoke = p_tcb-&TickSpokeP
& & if (p_spoke != (OS_TICK_SPOKE *)0) { & & & & & & & & & & & & & & &/* Confirm that task is in tick list & & & & & &*/
& & & & p_tcb-&TickRemain = (OS_TICK)0u;
& & & & if (p_spoke-&FirstPtr == p_tcb) { & & & & & & & & & & & & & & /* Is timer to remove at the beginning of list? */
& & & & & & p_tcb1 & & & & & &= (OS_TCB *)p_tcb-&TickNextP & & & & /* Yes & & & & & & & & & & & & & & & & & & & & &*/
& & & & & & p_spoke-&FirstPtr = p_tcb1;
/*其实,这我想说,一般延时时间到了的,多是在这解除,因为spoke上的任务,一定是就前面的时间先到*/
& & & & & & if (p_tcb1 != (OS_TCB *)0) {
& & & & & & & & p_tcb1-&TickPrevPtr = (void *)0;
& & & & & & }
& & & & } else {
& & & & & & p_tcb1 & & & & & & &= p_tcb-&TickPrevP & & & & & & & & /* No, remove timer from somewhere in the list &*/
& & & & & & p_tcb2 & & & & & & &= p_tcb-&TickNextP
& & & & & & p_tcb1-&TickNextPtr = p_tcb2;
& & & & & & if (p_tcb2 != (OS_TCB *)0) {
/*如果是调用了OSTimeDlyResume,才有可能执行到这,任务可能是在中间某位置解除*/
& & & & & & & & p_tcb2-&TickPrevPtr = p_tcb1;
& & & & & & }
& & & & p_tcb-&TickNextPtr &= (OS_TCB & & & &*)0;
& & & & p_tcb-&TickPrevPtr &= (OS_TCB & & & &*)0;
& & & & p_tcb-&TickSpokePtr = (OS_TICK_SPOKE *)0;
& & & & p_tcb-&TickCtrMatch = (OS_TICK & & & &)0u;
& & & & p_spoke-&NbrEntries--;
*************************************************************************************************************************/
/************************************************************************************************************************
字面上我们也可以看出来,如果解除延时的任务优先级和这个任务的相等,就把它放在这个优先级链上的最后,至于为什么我也不太明白,
可能是不想干扰到现在正在工作的任务吧。但我们大至可以猜到,这个刚被解除的任务可能原来是在当前任务之前的。
对于不等于当前任务优级的情况,其实可以这么看,如果是比当前任务优先级高,那么,当前任务能执行,说明比当前任务优先级高的
任务都处于阻塞的状态,而这个刚被解除的任务,所在的就绪链一定没别的任务,所以可以插到最前面,但也有可能是这样,被解除的任务
比当前的优先级低。比如,当前任务先运行一会,delay了,一个低优先级的运行一会也delay了,但马上那个任务就绪了,而低的还没有,
我们用这个就绪的任务解除了那个低优先级的,这也是有可能的,但这也说明,那个低优先级的任务在自己的任务链中原来也是在前面的,
因为我们们知道一个优先级链中,一定是执行第一个任务,但有没有可能那低优先级的任务不是在最前面的也是有可能的
比如优先级3上有一个任务A,优先级4上有两个任务B,C。A运行了一会,delay=5。B运行一会,然后delay=6,C运行一会,delay=10,
过一会,A动了,然后再一会B也就绪了,但A优先级高,所以还是A是当前任务,然后A将C的延时状态解除,看下面代码C一定会放在B前。
不过正常来说不会随便出现这种情况,而且,一般我们认为一个任务休息后应尽快工作,所以是放在优先级链前。
void &OS_RdyListInsert (OS_TCB *p_tcb)
& & OS_PrioInsert(p_tcb-&Prio);
& & if (p_tcb-&Prio == OSPrioCur) { & & & & & & & & & & & & /* Are we readying a task at the same prio? & & & & & & & */
& & & & OS_RdyListInsertTail(p_tcb); & & & & & & & & & & & &/* Yes, insert readied task at the end of the list & & & &*/
& & } else {
& & & & OS_RdyListInsertHead(p_tcb); & & & & & & & & & & & &/* No, &insert readied task at the beginning of the list &*/
只看这一个函数吧。比较简单。我也不说了,但为了逻辑连贯,我还是拿出来放在这。
void &OS_RdyListInsertTail (OS_TCB &*p_tcb)
& & OS_RDY_LIST &*p_rdy_
& & OS_TCB & & & *p_tcb2;
& & p_rdy_list = &OSRdyList[p_tcb-&Prio];
& & if (p_rdy_list-&NbrEntries == (OS_OBJ_QTY)0) { & & & & &/* CASE 0: Insert when there are no entries & & & & & & & */
& & & & p_rdy_list-&NbrEntries &= (OS_OBJ_QTY)1; & & & & & &/* & & & & This is the first entry & & & & & & & & & & & &*/
& & & & p_tcb-&NextPtr & & & & &= (OS_TCB & *)0; & & & & & &/* & & & & No other OS_TCBs in the list & & & & & & & & & */
& & & & p_tcb-&PrevPtr & & & & &= (OS_TCB & *)0;
& & & & p_rdy_list-&HeadPtr & & = p_ & & & & & & & & & &/* & & & & Both list pointers point to this OS_TCB & & & &*/
& & & & p_rdy_list-&TailPtr & & = p_
& & } else { & & & & & & & & & & & & & & & & & & & & & & & &/* CASE 1: Insert AFTER the current tail of list & & & & &*/
& & & & p_rdy_list-&NbrEntries++; & & & & & & & & & & & & & /* & & & & One more OS_TCB in the list & & & & & & & & & &*/
& & & & p_tcb-&NextPtr & & & & &= (OS_TCB & *)0; & & & & & &/* & & & & Adjust new OS_TCBs links & & & & & & & & & & & */
& & & & p_tcb2 & & & & & & & & &= p_rdy_list-&TailP
& & & & p_tcb-&PrevPtr & & & & &= p_tcb2;
& & & & p_tcb2-&NextPtr & & & & = p_ & & & & & & & & & &/* & & & & Adjust old tail of list's links & & & & & & & &*/
& & & & p_rdy_list-&TailPtr & & = p_
*************************************************************************************************************************
文章评论 以下网友留言只代表其个人观点,不代表本网站的观点和立场。

我要回帖

更多关于 如何学习ucos 的文章

 

随机推荐