ucosiii(1): 時鐘節拍函式

绿草蓝天發表於2024-07-19

時鐘節拍中斷呼叫OSTimeTick()函式

void  OSTimeTick (void)
{
    if (OSRunning != OS_STATE_OS_RUNNING) {
       return;
   }

>    OSTimeTickHook();                                           /* Call user definable hook                             */

#if (OS_CFG_SCHED_ROUND_ROBIN_EN > 0u)
    OS_SchedRoundRobin(&OSRdyList[OSPrioCur]);                  /* Update quanta ctr for the task which just ran        */
#endif

#if (OS_CFG_TICK_EN > 0u)
    OS_TickUpdate(1u);                                          /* Update from the ISR                                  */
#endif
}

1.呼叫自定義函式

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void  OSTimeTickHook (void)
{
#if OS_CFG_APP_HOOKS_EN > 0u
   if (OS_AppTimeTickHookPtr != (OS_APP_HOOK_VOID)0) {
       (*OS_AppTimeTickHookPtr)();
   }
#endif
}

2.時間片排程

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#if (OS_CFG_SCHED_ROUND_ROBIN_EN > 0u)
void  OS_SchedRoundRobin (OS_RDY_LIST  *p_rdy_list)
{
   OS_TCB  *p_tcb;
   CPU_SR_ALLOC();


   if (OSSchedRoundRobinEn != OS_TRUE) {                       /* Make sure round-robin has been enabled               */
       return;
   }

   CPU_CRITICAL_ENTER();
   p_tcb = p_rdy_list->HeadPtr;                                /* Decrement time quanta counter                        */

   if (p_tcb == (OS_TCB *)0) {
       CPU_CRITICAL_EXIT();
       return;
   }

#if (OS_CFG_TASK_IDLE_EN > 0u)
   if (p_tcb == &OSIdleTaskTCB) {
       CPU_CRITICAL_EXIT();
       return;
   }
#endif

   if (p_tcb->TimeQuantaCtr > 0u) {
       p_tcb->TimeQuantaCtr--;
   }

   if (p_tcb->TimeQuantaCtr > 0u) {                            /* Task not done with its time quanta                   */
       CPU_CRITICAL_EXIT();
       return;
   }

   if (p_rdy_list->HeadPtr == p_rdy_list->TailPtr) {           /* See if it's time to time slice current task          */
       CPU_CRITICAL_EXIT();                                    /* ... only if multiple tasks at same priority          */
       return;
   }

   if (OSSchedLockNestingCtr > 0u) {                           /* Can't round-robin if the scheduler is locked         */
       CPU_CRITICAL_EXIT();
       return;
   }

   OS_RdyListMoveHeadToTail(p_rdy_list);                       /* Move current OS_TCB to the end of the list           */
   p_tcb = p_rdy_list->HeadPtr;                                /* Point to new OS_TCB at head of the list              */
   if (p_tcb->TimeQuanta == 0u) {                              /* See if we need to use the default time slice         */
       p_tcb->TimeQuantaCtr = OSSchedRoundRobinDfltTimeQuanta;
   } else {
       p_tcb->TimeQuantaCtr = p_tcb->TimeQuanta;               /* Load time slice counter with new time                */
   }
   CPU_CRITICAL_EXIT();
}
#endif

2.1執行完時間片的程式放在尾部

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void  OS_RdyListMoveHeadToTail (OS_RDY_LIST  *p_rdy_list)
{
   OS_TCB  *p_tcb1;
   OS_TCB  *p_tcb2;
   OS_TCB  *p_tcb3;


    if (p_rdy_list->HeadPtr != p_rdy_list->TailPtr) {
        if (p_rdy_list->HeadPtr->NextPtr == p_rdy_list->TailPtr) { /* SWAP the TCBs                                    */
            p_tcb1              =  p_rdy_list->HeadPtr;        /* Point to current head                                */
            p_tcb2              =  p_rdy_list->TailPtr;        /* Point to current tail                                */
            p_tcb1->PrevPtr     =  p_tcb2;
            p_tcb1->NextPtr     = (OS_TCB *)0;
            p_tcb2->PrevPtr     = (OS_TCB *)0;
            p_tcb2->NextPtr     =  p_tcb1;
            p_rdy_list->HeadPtr =  p_tcb2;
            p_rdy_list->TailPtr =  p_tcb1;
        } else {
            p_tcb1              =  p_rdy_list->HeadPtr;        /* Point to current head                                */
            p_tcb2              =  p_rdy_list->TailPtr;        /* Point to current tail                                */
            p_tcb3              =  p_tcb1->NextPtr;            /* Point to new list head                               */
            p_tcb3->PrevPtr     = (OS_TCB *)0;                 /* Adjust back    link of new list head                 */
            p_tcb1->NextPtr     = (OS_TCB *)0;                 /* Adjust forward link of new list tail                 */
            p_tcb1->PrevPtr     =  p_tcb2;                     /* Adjust back    link of new list tail                 */
            p_tcb2->NextPtr     =  p_tcb1;                     /* Adjust forward link of old list tail                 */
            p_rdy_list->HeadPtr =  p_tcb3;                     /* Adjust new list head and tail pointers               */
            p_rdy_list->TailPtr =  p_tcb1;
        }
    }
}

3.更新節拍

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void  OS_TickUpdate (OS_TICK  ticks)
{
#if (OS_CFG_TS_EN > 0u)
   CPU_TS  ts_start;
#endif
   CPU_SR_ALLOC();


   CPU_CRITICAL_ENTER();

   OSTickCtr += ticks;                                         /* Keep track of the number of ticks                    */

   OS_TRACE_TICK_INCREMENT(OSTickCtr);

#if (OS_CFG_TS_EN > 0u)
   ts_start   = OS_TS_GET();
   OS_TickListUpdate(ticks);
   OSTickTime = OS_TS_GET() - ts_start;
   if (OSTickTimeMax < OSTickTime) {
       OSTickTimeMax = OSTickTime;
   }
#else
   OS_TickListUpdate(ticks);
#endif

#if (OS_CFG_DYN_TICK_EN > 0u)
   if (OSTickList.TCB_Ptr != (OS_TCB *)0) {
       OSTickCtrStep = OSTickList.TCB_Ptr->TickRemain;
   } else {
       OSTickCtrStep = 0u;
   }

   OS_DynTickSet(OSTickCtrStep);
#endif
   CPU_CRITICAL_EXIT();
}

3.1更新節拍列表

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
static  void  OS_TickListUpdate (OS_TICK  ticks)
{
   OS_TCB        *p_tcb;
   OS_TICK_LIST  *p_list;
#if (OS_CFG_DBG_EN > 0u)
   OS_OBJ_QTY     nbr_updated;
#endif
#if (OS_CFG_MUTEX_EN > 0u)
   OS_TCB        *p_tcb_owner;
   OS_PRIO        prio_new;
#endif



#if (OS_CFG_DBG_EN > 0u)
   nbr_updated = 0u;
#endif
   p_list      = &OSTickList;
   p_tcb       = p_list->TCB_Ptr;
   if (p_tcb != (OS_TCB *)0) {
       if (p_tcb->TickRemain <= ticks) {
           ticks              = ticks - p_tcb->TickRemain;
           p_tcb->TickRemain  = 0u;
       } else {
           p_tcb->TickRemain -= ticks;
       }

       while (p_tcb->TickRemain == 0u) {
#if (OS_CFG_DBG_EN > 0u)
           nbr_updated++;
#endif

           switch (p_tcb->TaskState) {
               case OS_TASK_STATE_DLY:
                    p_tcb->TaskState = OS_TASK_STATE_RDY;
                    OS_RdyListInsert(p_tcb);                            /* Insert the task in the ready list                    */
                    break;

               case OS_TASK_STATE_DLY_SUSPENDED:
                    p_tcb->TaskState = OS_TASK_STATE_SUSPENDED;
                    break;

               default:
#if (OS_CFG_MUTEX_EN > 0u)
                    p_tcb_owner = (OS_TCB *)0;
                    if (p_tcb->PendOn == OS_TASK_PEND_ON_MUTEX) {
                        p_tcb_owner = (OS_TCB *)((OS_MUTEX *)((void *)p_tcb->PendObjPtr))->OwnerTCBPtr;
                    }
#endif

#if (OS_MSG_EN > 0u)
                    p_tcb->MsgPtr  = (void *)0;
                    p_tcb->MsgSize = 0u;
#endif
#if (OS_CFG_TS_EN > 0u)
                    p_tcb->TS      = OS_TS_GET();
#endif
                    OS_PendListRemove(p_tcb);                           /* Remove task from pend list                           */

                    switch (p_tcb->TaskState) {
                        case OS_TASK_STATE_PEND_TIMEOUT:
                             OS_RdyListInsert(p_tcb);                   /* Insert the task in the ready list                    */
                             p_tcb->TaskState  = OS_TASK_STATE_RDY;
                             break;

                        case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:
                             p_tcb->TaskState  = OS_TASK_STATE_SUSPENDED;
                             break;

                        default:
                             break;
                    }
                    p_tcb->PendStatus = OS_STATUS_PEND_TIMEOUT;         /* Indicate pend timed out                              */
                    p_tcb->PendOn     = OS_TASK_PEND_ON_NOTHING;        /* Indicate no longer pending                           */

#if (OS_CFG_MUTEX_EN > 0u)
                    if (p_tcb_owner != (OS_TCB *)0) {
                        if ((p_tcb_owner->Prio != p_tcb_owner->BasePrio) &&
                            (p_tcb_owner->Prio == p_tcb->Prio)) {       /* Has the owner inherited a priority?                  */
                            prio_new = OS_MutexGrpPrioFindHighest(p_tcb_owner);
                            prio_new = (prio_new > p_tcb_owner->BasePrio) ? p_tcb_owner->BasePrio : prio_new;
                            if (prio_new != p_tcb_owner->Prio) {
                                OS_TaskChangePrio(p_tcb_owner, prio_new);
                                OS_TRACE_MUTEX_TASK_PRIO_DISINHERIT(p_tcb_owner, p_tcb_owner->Prio);
                            }
                        }
                    }
#endif
                    break;
           }

           p_list->TCB_Ptr = p_tcb->TickNextPtr;
           p_tcb           = p_list->TCB_Ptr;                           /* Get 'p_tcb' again for loop                           */
           if (p_tcb == (OS_TCB *)0) {
#if (OS_CFG_DBG_EN > 0u)
               p_list->NbrEntries = 0u;
#endif
               break;
           } else {
#if (OS_CFG_DBG_EN > 0u)
               p_list->NbrEntries--;
#endif
               p_tcb->TickPrevPtr = (OS_TCB *)0;
               if (p_tcb->TickRemain <= ticks) {
                   ticks              = ticks - p_tcb->TickRemain;
                   p_tcb->TickRemain  = 0u;
               } else {
                   p_tcb->TickRemain -= ticks;
               }
           }
       }
   }
#if (OS_CFG_DBG_EN > 0u)
   p_list->NbrUpdated = nbr_updated;
#endif
}

3.1.1插入就緒列表

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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*/
   }

   OS_TRACE_TASK_READY(p_tcb);
}

3.1.1.1插入優先順序

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void  OS_PrioInsert (OS_PRIO  prio)
{
#if   (OS_CFG_PRIO_MAX <= (CPU_CFG_DATA_SIZE * 8u))             /* Optimize for less than word size nbr of priorities   */
   OSPrioTbl[0] |= (CPU_DATA)1u << (((CPU_CFG_DATA_SIZE * 8u) - 1u) - prio);


#elif (OS_CFG_PRIO_MAX <= (2u * (CPU_CFG_DATA_SIZE * 8u)))      /* Optimize for    2x the word size nbr of priorities   */
   if (prio < (CPU_CFG_DATA_SIZE * 8u)) {
       OSPrioTbl[0] |= (CPU_DATA)1u << (((CPU_CFG_DATA_SIZE * 8u) - 1u) - prio);
   } else {
       OSPrioTbl[1] |= (CPU_DATA)1u << (((CPU_CFG_DATA_SIZE * 8u) - 1u) - (prio - (CPU_CFG_DATA_SIZE * 8u)));
   }


#else
   CPU_DATA  bit_nbr;
   OS_PRIO   ix;

   ix             = (OS_PRIO)(prio /  (CPU_CFG_DATA_SIZE * 8u));
   bit_nbr        = (CPU_DATA)prio & ((CPU_CFG_DATA_SIZE * 8u) - 1u);
   OSPrioTbl[ix] |= (CPU_DATA)1u << (((CPU_CFG_DATA_SIZE * 8u) - 1u) - bit_nbr);
#endif
}

3.1.1.2插入就緒列表尾部

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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->HeadPtr == (OS_TCB *)0) {                   /* CASE 0: Insert when there are no entries             */
#if (OS_CFG_DBG_EN > 0u)
       p_rdy_list->NbrEntries  =           1u;                 /* This is the first entry                              */
#endif
       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        */
#if (OS_CFG_DBG_EN > 0u)
       p_rdy_list->NbrEntries++;                               /* One more OS_TCB in the list                          */
#endif
       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;
   }
}

3.1.1.3插入就緒列表頭部

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void  OS_RdyListInsertHead (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->HeadPtr == (OS_TCB *)0) {                   /* CASE 0: Insert when there are no entries             */
#if (OS_CFG_DBG_EN > 0u)
       p_rdy_list->NbrEntries =           1u;                  /* This is the first entry                              */
#endif
       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 BEFORE the current head of list       */
#if (OS_CFG_DBG_EN > 0u)
       p_rdy_list->NbrEntries++;                               /* One more OS_TCB in the list                          */
#endif
       p_tcb->NextPtr         =  p_rdy_list->HeadPtr;          /* Adjust new OS_TCBs links                             */
       p_tcb->PrevPtr         = (OS_TCB *)0;
       p_tcb2                 =  p_rdy_list->HeadPtr;          /* Adjust old head of list's links                      */
       p_tcb2->PrevPtr        =  p_tcb;
       p_rdy_list->HeadPtr    =  p_tcb;
   }
}

3.1.2從掛起列表移除

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void  OS_PendListRemove (OS_TCB  *p_tcb)
{
   OS_PEND_LIST  *p_pend_list;
   OS_TCB        *p_next;
   OS_TCB        *p_prev;


   if (p_tcb->PendObjPtr != (OS_PEND_OBJ *)0) {                /* Only remove if object has a pend list.               */
       p_pend_list = &p_tcb->PendObjPtr->PendList;             /* Get pointer to pend list                             */

                                                               /* Remove TCB from the pend list.                       */
       if (p_pend_list->HeadPtr->PendNextPtr == (OS_TCB *)0) {
           p_pend_list->HeadPtr = (OS_TCB *)0;                 /* Only one entry in the pend list                      */
           p_pend_list->TailPtr = (OS_TCB *)0;
       } else if (p_tcb->PendPrevPtr == (OS_TCB *)0) {         /* See if entry is at the head of the list              */
           p_next               =  p_tcb->PendNextPtr;         /* Yes                                                  */
           p_next->PendPrevPtr  = (OS_TCB *)0;
           p_pend_list->HeadPtr =  p_next;

       } else if (p_tcb->PendNextPtr == (OS_TCB *)0) {         /* See if entry is at the tail of the list              */
           p_prev               =  p_tcb->PendPrevPtr;         /* Yes                                                  */
           p_prev->PendNextPtr  = (OS_TCB *)0;
           p_pend_list->TailPtr =  p_prev;

       } else {
           p_prev               = p_tcb->PendPrevPtr;          /* Remove from inside the list                          */
           p_next               = p_tcb->PendNextPtr;
           p_prev->PendNextPtr  = p_next;
           p_next->PendPrevPtr  = p_prev;
       }
#if (OS_CFG_DBG_EN > 0u)
       p_pend_list->NbrEntries--;                              /* One less entry in the list                           */
#endif
       p_tcb->PendNextPtr = (OS_TCB      *)0;
       p_tcb->PendPrevPtr = (OS_TCB      *)0;
       p_tcb->PendObjPtr  = (OS_PEND_OBJ *)0;
   }
}

3.1.3獲取互斥量最高優先權

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
OS_PRIO  OS_MutexGrpPrioFindHighest (OS_TCB  *p_tcb)
{
   OS_MUTEX  **pp_mutex;
   OS_PRIO     highest_prio;
   OS_PRIO     prio;
   OS_TCB     *p_head;


   highest_prio = (OS_PRIO)(OS_CFG_PRIO_MAX - 1u);
   pp_mutex = &p_tcb->MutexGrpHeadPtr;

   while(*pp_mutex != (OS_MUTEX *)0) {
       p_head = (*pp_mutex)->PendList.HeadPtr;
       if (p_head != (OS_TCB *)0) {
           prio = p_head->Prio;
           if(prio < highest_prio) {
               highest_prio = prio;
           }
       }
       pp_mutex = &(*pp_mutex)->MutexGrpNextPtr;
   }

   return (highest_prio);
}

3.1.4改變執行任務優先權

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void  OS_TaskChangePrio(OS_TCB  *p_tcb,
                       OS_PRIO  prio_new)
{
   OS_TCB  *p_tcb_owner;
#if (OS_CFG_MUTEX_EN > 0u)
   OS_PRIO  prio_cur;
#endif


   do {
       p_tcb_owner = (OS_TCB *)0;
#if (OS_CFG_MUTEX_EN > 0u)
       prio_cur    =  p_tcb->Prio;
#endif
       switch (p_tcb->TaskState) {
           case OS_TASK_STATE_RDY:
                OS_RdyListRemove(p_tcb);                       /* Remove from current priority                         */
                p_tcb->Prio = prio_new;                        /* Set new task priority                                */
                OS_PrioInsert(p_tcb->Prio);
                if (p_tcb == OSTCBCurPtr) {
                    OS_RdyListInsertHead(p_tcb);
                } else {
                    OS_RdyListInsertTail(p_tcb);
                }
                break;

           case OS_TASK_STATE_DLY:                             /* Nothing to do except change the priority in the OS_TCB*/
           case OS_TASK_STATE_SUSPENDED:
           case OS_TASK_STATE_DLY_SUSPENDED:
                p_tcb->Prio = prio_new;                        /* Set new task priority                                */
                break;

           case OS_TASK_STATE_PEND:
           case OS_TASK_STATE_PEND_TIMEOUT:
           case OS_TASK_STATE_PEND_SUSPENDED:
           case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:
                p_tcb->Prio = prio_new;                        /* Set new task priority                                */
                switch (p_tcb->PendOn) {                       /* What to do depends on what we are pending on         */
                    case OS_TASK_PEND_ON_FLAG:
                    case OS_TASK_PEND_ON_Q:
                    case OS_TASK_PEND_ON_SEM:
                         OS_PendListChangePrio(p_tcb);
                         break;

                    case OS_TASK_PEND_ON_MUTEX:
#if (OS_CFG_MUTEX_EN > 0u)
                         OS_PendListChangePrio(p_tcb);
                         p_tcb_owner = ((OS_MUTEX *)((void *)p_tcb->PendObjPtr))->OwnerTCBPtr;
                         if (prio_cur > prio_new) {            /* Are we increasing the priority?                      */
                             if (p_tcb_owner->Prio <= prio_new) { /* Yes, do we need to give this prio to the owner?   */
                                 p_tcb_owner = (OS_TCB *)0;
                             } else {
                                                               /* Block is empty when trace is disabled.               */
                                OS_TRACE_MUTEX_TASK_PRIO_INHERIT(p_tcb_owner, prio_new);
                             }
                         } else {
                             if (p_tcb_owner->Prio == prio_cur) { /* No, is it required to check for a lower prio?     */
                                 prio_new = OS_MutexGrpPrioFindHighest(p_tcb_owner);
                                 prio_new = (prio_new > p_tcb_owner->BasePrio) ? p_tcb_owner->BasePrio : prio_new;
                                 if (prio_new == p_tcb_owner->Prio) {
                                     p_tcb_owner = (OS_TCB *)0;
                                 } else {
                                                               /* Block is empty when trace is disabled.               */
                                    OS_TRACE_MUTEX_TASK_PRIO_DISINHERIT(p_tcb_owner, prio_new);
                                 }
                             } else {
                                 p_tcb_owner = (OS_TCB *)0;
                             }
                         }
#endif
                         break;

                    case OS_TASK_PEND_ON_TASK_Q:
                    case OS_TASK_PEND_ON_TASK_SEM:
                    default:
                                                               /* Default case.                                        */
                         break;
                }
                break;

           default:
                return;
       }
       p_tcb = p_tcb_owner;
   } while (p_tcb != (OS_TCB *)0);
}

相關文章