ucos 时钟节拍_ucos-iii时钟节拍

这回说下系统中很重要的时钟节拍

在系统初始化的时候就用下面这个函数建了一个时钟任务。

/************************************************************************************************************************

void  OS_TickTaskInit (OS_ERR  *p_err)

{

#ifdef OS_SAFETY_CRITICAL

if (p_err == (OS_ERR *)0) {

OS_SAFETY_CRITICAL_EXCEPTION();

return;

}

#endif

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;

return;

}

/*下面是建时钟节拍任务*/

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   i;

OS_TICK_SPOKE     *p_spoke;

/*如果一个任务休息了,那它会从就绪列中退出,然后用OS_TICK_SPOKE来管理*/

for (i = 0u; i < OSCfg_TickWheelSize; 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              *FirstPtr;                          /* 这里怎么说呢比如挂OSCfg_TickWheel[1]任务可能有很多,但这里的

FirstPtr只指第一个任务,其他任务是用任务控制块中的成员TickNextPtr,TickPrevPtr来连接的*/

OS_OBJ_QTY           NbrEntries;                        /* 还是用OSCfg_TickWheel[1]举例,挂要这个spoke上的任务数            */

OS_OBJ_QTY           NbrEntriesMax;                     /* 这上的最多可以是多少个任务,(这说的不一定对)               */

};

OSCfg_TickWheel对于这个大家先别急,等我说到OSTimeDly说,这节会说的。

*************************************************************************************************************************/

/************************************************************************************************************************

这个任务是在上面的函数中建立的。

void  OS_TickTask (void *p_arg)

{

OS_ERR  err;

CPU_TS  ts;

p_arg = p_arg;                                          /* 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  err;

#if OS_CFG_ISR_POST_DEFERRED_EN > 0u

CPU_TS  ts;

#endif

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);

#else

(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]);

#endif

#if OS_CFG_TMR_EN > 0u

OSTmrUpdateCtr--;/*这是用于软定时器的先不说了*/

if (OSTmrUpdateCtr == (OS_CTR)0u) {

OSTmrUpdateCtr = OSTmrUpdateCnt;

OSTaskSemPost((OS_TCB *)&OSTmrTaskTCB,              /* Signal timer task                                      */

(OS_OPT  ) OS_OPT_POST_NONE,

(OS_ERR *)&err);

}

#endif

#endif

}

*************************************************************************************************************************/

/************************************************************************************************************************

好了说下任务的延时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();

return;

}

#endif

#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;

return;

}

#endif

if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0u) {       /* Can't delay when the scheduler is locked               */

*p_err = OS_ERR_SCHED_LOCKED;

return;

}

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;

return;

}

break;

case OS_OPT_TIME_MATCH:

break;

default:

*p_err = OS_ERR_OPT_INVALID;

return;

}

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();

return;

}

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_delta;

OS_TICK            tick_next;

OS_TICK_SPOKE     *p_spoke;

OS_TCB            *p_tcb0;

OS_TCB            *p_tcb1;

OS_TICK_SPOKE_IX   spoke;

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,那就不会让任务休息了,但要是0x00000005,这样是会让任务休息的*/

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.                                 */

return;

}

p_tcb->TickCtrMatch = time;

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 + time;

tick_delta = tick_next - OSTickCtr - 1u;

if (tick_delta < time) {                             /* If next periodic delay did NOT already occur, ... */

p_tcb->TickCtrMatch = tick_next;                 /* ... set  next  periodic delay;                ... */

} else {

p_tcb->TickCtrMatch = OSTickCtr + time;          /* ... else reset periodic delay.                    */

}

p_tcb->TickRemain   = p_tcb->TickCtrMatch - OSTickCtr;

p_tcb->TickCtrPrev  = p_tcb->TickCtrMatch;

} else {                                                 /*OS_OPT_TIME_DLY还有这种,就是让任务休息time时间                 */

p_tcb->TickCtrMatch = OSTickCtr + time;

p_tcb->TickRemain   = time;

}

/*综上所述,根据我们的选项设置了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 {                                                     /* Zero time delay; ...                              */

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.                                 */

return;

}

/*然后用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_tcb;

p_spoke->NbrEntries  = (OS_OBJ_QTY)1u;

} else {

p_tcb1     = p_spoke->FirstPtr;                          /* 如果不是,就把这个任务插到这个链中,            */

while (p_tcb1 != (OS_TCB *)0) {

p_tcb1->TickRemain = p_tcb1->TickCtrMatch- OSTickCtr;            /* 看这几行,我们发现,当前任务要插在,一个合适的位置,也就是当前任务插在那个位置后,

一定是这个任务前面的任务所需的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->TickNextPtr; /* No,  Point to next TCB in the list                */

} else {

p_tcb->TickNextPtr   = (OS_TCB *)0;

p_tcb->TickPrevPtr   =  p_tcb1;

p_tcb1->TickNextPtr  =  p_tcb;               /* 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_tcb;

p_spoke->FirstPtr    =  p_tcb;

} else {                                         /* Insert in between 2 TCBs already in the list      */

p_tcb0               =  p_tcb1->TickPrevPtr;

p_tcb->TickPrevPtr   =  p_tcb0;

p_tcb->TickNextPtr   =  p_tcb1;

p_tcb0->TickNextPtr  =  p_tcb;

p_tcb1->TickPrevPtr  =  p_tcb;

}

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->NbrEntries;

}

p_tcb->TickSpokePtr = p_spoke;                               /* Link back to tick spoke                           */

*p_err               = OS_ERR_NONE;

}

画个图来看一个

spoke

+-------------+________

| FirstPtr    |    |

+-------------+|  tcb1tcb2                 tcb2

|NbrEntries=3 |   |---->+-----------+      +-----------+      +-----------+

+-------------+   0

|NbrEntriesMax|   +-----------+       +-----------+       +-----------+

+-------------+          |TickNextPtr|-----> |TickNextPtr|-----> |TickNextPtr|-----> 0

+-----------+       +-----------+       +-----------+

*************************************************************************************************************************/

/************************************************************************************************************************

我们在看一下OS_Ticktask任务做的事OS_TickListUpdate();就是看看当前时间没有没任务延时结束,只看OSCfg_TickWheel[OSTickCtr % OSCfg_TickWheelSize]上的任务,

而且先看第一个如果第一个延时结束才会向后看,因为后面的延时时间都是大于等于前面的,前面的不就绪,后面的也不可能就绪,这样做就很高效,实时性就好

void  OS_TickListUpdate (void)

{

CPU_BOOLEAN        done;

OS_TICK_SPOKE     *p_spoke;

OS_TCB            *p_tcb;

OS_TCB            *p_tcb_next;

OS_TICK_SPOKE_IX   spoke;

CPU_TS             ts_start;

CPU_TS             ts_end;

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->FirstPtr;

done     = DEF_FALSE;

while (done == DEF_FALSE) {

if (p_tcb != (OS_TCB *)0) {

p_tcb_next = p_tcb->TickNextPtr;                           /* 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:

break;

case OS_TASK_STATE_DLY:

p_tcb->TickRemain = p_tcb->TickCtrMatch           /* Compute time remaining of current TCB       */

- OSTickCtr;

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小的在前面,

如果最前面的任务都没就绪,后面的也不会就绪,所以就不向下看了*/

}

break;

case OS_TASK_STATE_PEND_TIMEOUT:

p_tcb->TickRemain = p_tcb->TickCtrMatch           /* 这个是在等事件时用的,一般我们不会让任务无限等那个事件,有时间限制的,时间到了,也会就绪       */

- OSTickCtr;

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;

#endif

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!             */

}

break;

case OS_TASK_STATE_DLY_SUSPENDED:/*这个位置我想说的是SUSPENDED,说的是待机状态(我也不知道可不可以这么说就是闲着没事),

以上都是延时结束,就会进入就绪,有了这个状态就是延时结束也不会就绪*/

p_tcb->TickRemain = p_tcb->TickCtrMatch           /* Compute time remaining of current TCB       */

- OSTickCtr;

if (OSTickCtr == p_tcb->TickCtrMatch) {           /*OSTickCtr等于这个任务的 TickCtrMatch结束延时               */

p_tcb->TaskState  = OS_TASK_STATE_SUSPENDED;

OS_TickListRemove(p_tcb);                     /* 你看,虽然从这个链上拿下来了,但也没调用进入就绪状态那个函数,而且不就绪也不是因为延时或等事件*/

} else {

done              = DEF_TRUE;                 /* 这个地方我不说了,上面说过了           */

}

break;

case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:

p_tcb->TickRemain = p_tcb->TickCtrMatch           /* Compute time remaining of current TCB       */

- OSTickCtr;

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;

#endif

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!             */

}

break;

default:

break;

}

p_tcb = p_tcb_next;

} else {

done  = DEF_TRUE;

}

}

ts_end = OS_TS_GET() - ts_start;                                   /* 看这个函数执行了多少时间,也是验证实时性的,时间越短越好         */

if (ts_end > OSTickTaskTimeMax) {

OSTickTaskTimeMax = ts_end;

}

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();

return;

}

#endif

#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;

return;

}

#endif

#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;

return;

}

#endif

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;

break;

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;

break;

case OS_TASK_STATE_PEND:

CPU_CRITICAL_EXIT();

*p_err = OS_ERR_TASK_NOT_DLY;

break;

case OS_TASK_STATE_PEND_TIMEOUT:

CPU_CRITICAL_EXIT();

*p_err = OS_ERR_TASK_NOT_DLY;

break;

case OS_TASK_STATE_SUSPENDED:

CPU_CRITICAL_EXIT();

*p_err = OS_ERR_TASK_NOT_DLY;

break;

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;

break;

case OS_TASK_STATE_PEND_SUSPENDED:

CPU_CRITICAL_EXIT();

*p_err = OS_ERR_TASK_NOT_DLY;

break;

case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:

CPU_CRITICAL_EXIT();

*p_err = OS_ERR_TASK_NOT_DLY;

break;

default:

CPU_CRITICAL_EXIT();

*p_err = OS_ERR_STATE_INVALID;

break;

}

OSSched();

}

*************************************************************************************************************************/

/************************************************************************************************************************

将任务从管理它的spoke上卸下,这个任务不在指向这个spoke,这个spoke也不指向这个任务。这个任务不再指向这个spoke上的其他任务,

这个spoke上的其他任务也不指向它。

void  OS_TickListRemove (OS_TCB  *p_tcb)

{

OS_TICK_SPOKE  *p_spoke;

OS_TCB         *p_tcb1;

OS_TCB         *p_tcb2;

p_spoke = p_tcb->TickSpokePtr;

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->TickNextPtr;         /* Yes                                          */

p_spoke->FirstPtr = p_tcb1;/*其实,这我想说,一般延时时间到了的,多是在这解除,因为spoke上的任务,一定是就前面的时间先到*/

if (p_tcb1 != (OS_TCB *)0) {

p_tcb1->TickPrevPtr = (void *)0;

}

} else {

p_tcb1              = p_tcb->TickPrevPtr;                 /* No, remove timer from somewhere in the list  */

p_tcb2              = p_tcb->TickNextPtr;

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_list;

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_tcb;                    /*         Both list pointers point to this OS_TCB        */

p_rdy_list->TailPtr     = p_tcb;

} 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->TailPtr;

p_tcb->PrevPtr          = p_tcb2;

p_tcb2->NextPtr         = p_tcb;                    /*         Adjust old tail of list's links                */

p_rdy_list->TailPtr     = p_tcb;

}

}

*************************************************************************************************************************

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值