μCOS-III

μCOS-III 是一个全新的 RTOS 内核,不要将它看成 μCOS-II 的升级版。

【todo】

二、内核源代码分析

2.1 任务调度

此部分包含:(任务调度)与(就绪任务优先级、就绪任务优先级列表的实时更新维护)两部分内核功能( internal feature/services )。

代码很清晰,直接展示代码:


/* 此部分代码实现了实现了任务调度功能。Version : uC/OS-III V3.08.02  */

/*
** 1.  任务调度: 获取最高就绪优先级 和 获取最高优先级链表中需要接下来运行的任务。
** 1.1 使用前置导零的汇编指令,硬件级别支持快速查找最高优先级所在的位。
** 1.2 按照最大优先级数量,进行了三种情况的代码优化:预编译实现代码选择。
** 1.3 获取最高优先级链表中需要接下来运行的任务: 
**     OSSched   函数: 任务代码中调用。
**     OSIntExit 函数: 中断ISR代码中调用。 OSIntEnter() and OSIntExit() 必须成对使用。
*/ 
/*
************************************************************************************************************************
*                                           GET HIGHEST PRIORITY TASK WAITING
*
* Description: This function is called by other uC/OS-III services to determine the highest priority task
*              waiting on the event.
*
* Arguments  : none
*
* Returns    : The priority of the Highest Priority Task (HPT) waiting for the event
*
* Note(s)    : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
************************************************************************************************************************
*/

OS_PRIO  OS_PrioGetHighest (void)
{
#if   (OS_CFG_PRIO_MAX <= (CPU_CFG_DATA_SIZE * 8u))             /* Optimize for less than word size nbr of priorities   */
    return ((OS_PRIO)CPU_CntLeadZeros(OSPrioTbl[0]));           


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


#else
    CPU_DATA  *p_tbl;
    OS_PRIO    prio;


    prio  = 0u;
    p_tbl = &OSPrioTbl[0];
    while (*p_tbl == 0u) {                                      /* Search the bitmap table for the highest priority     */
        prio = (OS_PRIO)(prio + (CPU_CFG_DATA_SIZE * 8u));      /* Compute the step of each CPU_DATA entry              */
        p_tbl++;
    }
    prio += (OS_PRIO)CPU_CntLeadZeros(*p_tbl);                  /* Find the position of the first bit set at the entry  */

    return (prio);
#endif
}


/*
************************************************************************************************************************
*                                                      SCHEDULER
*
* Description: This function is called by other uC/OS-III services to determine whether a new, high priority task has
*              been made ready to run.  This function is invoked by TASK level code and is not used to reschedule tasks
*              from ISRs (see OSIntExit() for ISR rescheduling).
*
* Arguments  : none
*
* Returns    : none
*
* Note(s)    : 1) Rescheduling is prevented when the scheduler is locked (see OSSchedLock())
************************************************************************************************************************
*/

void  OSSched (void)
{
    CPU_SR_ALLOC();


#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u)                       /* Can't schedule when the kernel is stopped.           */
    if (OSRunning != OS_STATE_OS_RUNNING) {
        return;
    }
#endif

    if (OSIntNestingCtr > 0u) {                                 /* ISRs still nested?                                   */
        return;                                                 /* Yes ... only schedule when no nested ISRs            */
    }

    if (OSSchedLockNestingCtr > 0u) {                           /* Scheduler locked?                                    */
        return;                                                 /* Yes                                                  */
    }

    CPU_INT_DIS();
    OSPrioHighRdy   = OS_PrioGetHighest();                      /* Find the highest priority ready   获取最高就绪优先级    */
#if (OS_CFG_TASK_IDLE_EN > 0u)                                  
    OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr;         /* 找到最高优先级链表中需要运行的那个任务(ready-to-run)       */
    if (OSTCBHighRdyPtr == OSTCBCurPtr) {                       /* 当前运行的任务仍然处于最高优先级?                        */
        CPU_INT_EN();                                           /* Yes                                                  */
        return;
    }
#else // 若对 OS_CFG_TASK_IDLE_EN 数值有疑问,可参见 OS_PrioInit 函数。
    if (OSPrioHighRdy != (OS_CFG_PRIO_MAX - 1u)) {    /* 最高就绪任务优先级是不是空闲任务的优先级?(注:空闲任务的优先级只有空闲任务)*/
        OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr;     /* 若不是,则找到最高优先级链表中需要运行的那个任务(ready-to-run) */
        if (OSTCBHighRdyPtr == OSTCBCurPtr) {                   /* 当前运行的任务仍然处于最高优先级?                */
            CPU_INT_EN();                                       /* Yes                                                    */
            return;
        }
    }
#endif

    OS_TRACE_TASK_PREEMPT(OSTCBCurPtr);

#if (OS_CFG_TASK_PROFILE_EN > 0u)
    OSTCBHighRdyPtr->CtxSwCtr++;                                /* Inc. # of context switches to this task              */
#endif

#if ((OS_CFG_TASK_PROFILE_EN > 0u) || (OS_CFG_DBG_EN > 0u))
    OSTaskCtxSwCtr++;                                           /* Increment context switch counter                     */
#endif

#if defined(OS_CFG_TLS_TBL_SIZE) && (OS_CFG_TLS_TBL_SIZE > 0u)
    OS_TLS_TaskSw();
#endif

#if (OS_CFG_TASK_IDLE_EN > 0u)
    OS_TASK_SW();                                               /* Perform a task level context switch                  */
    CPU_INT_EN();
#else
    if ((OSPrioHighRdy != (OS_CFG_PRIO_MAX - 1u))) {
        OS_TASK_SW();                                           /* Perform a task level context switch                  */
        CPU_INT_EN();
    } else {
        OSTCBHighRdyPtr = OSTCBCurPtr;
        CPU_INT_EN();
        for (;;) {
#if ((OS_CFG_DBG_EN > 0u) || (OS_CFG_STAT_TASK_EN > 0u))
            CPU_CRITICAL_ENTER();
#if (OS_CFG_DBG_EN > 0u)
            OSIdleTaskCtr++;
#endif
#if (OS_CFG_STAT_TASK_EN > 0u)
            OSStatTaskCtr++;
#endif
            CPU_CRITICAL_EXIT();
#endif

#if (OS_CFG_APP_HOOKS_EN > 0u)
            OSIdleTaskHook();                                   /* Call user definable HOOK                             */
#endif
            if ((*((volatile OS_PRIO *)&OSPrioHighRdy) != (OS_CFG_PRIO_MAX - 1u))) {
                break;
            }
        }
    }
#endif

#ifdef OS_TASK_SW_SYNC
    OS_TASK_SW_SYNC();
#endif
}


/*
************************************************************************************************************************
*                                                       EXIT ISR
*
* Description: This function is used to notify uC/OS-III that you have completed servicing an ISR.  When the last nested
*              ISR has completed, uC/OS-III will call the scheduler to determine whether a new, high-priority task, is
*              ready to run.
*
* Arguments  : none
*
* Returns    : none
*
* Note(s)    : 1) You MUST invoke OSIntEnter() and OSIntExit() in pair.  In other words, for every call to OSIntEnter()
*                 (or direct increment to OSIntNestingCtr) at the beginning of the ISR you MUST have a call to OSIntExit()
*                 at the end of the ISR.
*
*              2) Rescheduling is prevented when the scheduler is locked (see OSSchedLock())
************************************************************************************************************************
*/

void  OSIntExit (void)
{
#if (OS_CFG_TASK_STK_REDZONE_EN > 0u)
    CPU_BOOLEAN  stk_status;
#endif
    CPU_SR_ALLOC();



    if (OSRunning != OS_STATE_OS_RUNNING) {                     /* Has the OS started?                                  */
        OS_TRACE_ISR_EXIT();
        return;                                                 /* No                                                   */
    }

    CPU_INT_DIS();
    if (OSIntNestingCtr == 0u) {                                /* Prevent OSIntNestingCtr from wrapping                */
        OS_TRACE_ISR_EXIT();
        CPU_INT_EN();
        return;
    }
    OSIntNestingCtr--;
    if (OSIntNestingCtr > 0u) {                                 /* ISRs still nested?                                   */
        OS_TRACE_ISR_EXIT();
        CPU_INT_EN();                                           /* Yes                                                  */
        return;
    }

    if (OSSchedLockNestingCtr > 0u) {                           /* Scheduler still locked?                              */
        OS_TRACE_ISR_EXIT();
        CPU_INT_EN();                                           /* Yes                                                  */
        return;
    }

                                                                /* Verify ISR Stack                                     */
#if (OS_CFG_ISR_STK_SIZE > 0u)
#if (OS_CFG_TASK_STK_REDZONE_EN > 0u)
    stk_status = OS_TaskStkRedzoneChk(OSCfg_ISRStkBasePtr, OSCfg_ISRStkSize);
    if (stk_status != OS_TRUE) {
        OSRedzoneHitHook((OS_TCB *)0);
    }
#endif
#endif

    OSPrioHighRdy   = OS_PrioGetHighest();                      /* Find highest priority      获取最高就绪优先级           */
#if (OS_CFG_TASK_IDLE_EN > 0u)
    OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr;         /* 找到最高优先级链表中需要运行的那个任务(ready-to-run)       */
    if (OSTCBHighRdyPtr == OSTCBCurPtr) {                       /* Current task still the highest priority?             */
                                                                /* Yes                                                  */
#if (OS_CFG_TASK_STK_REDZONE_EN > 0u)
        stk_status = OSTaskStkRedzoneChk((OS_TCB *)0);
        if (stk_status != OS_TRUE) {
            OSRedzoneHitHook(OSTCBCurPtr);
        }
#endif
        OS_TRACE_ISR_EXIT();
        CPU_INT_EN();
        OS_TRACE_TASK_SWITCHED_IN(OSTCBHighRdyPtr);             /* Do this here because we don't execute OSIntCtxSw().  */
        return;
    }
#else
    if (OSPrioHighRdy != (OS_CFG_PRIO_MAX - 1u)) {              /* Are we returning to idle?                            */
        OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr;     /* No ... get highest priority task ready-to-run        */
        if (OSTCBHighRdyPtr == OSTCBCurPtr) {                   /* Current task still the highest priority?             */
                                                                /* Yes                                                  */
            OS_TRACE_ISR_EXIT();
            CPU_INT_EN();
            OS_TRACE_TASK_SWITCHED_IN(OSTCBHighRdyPtr);         /* Do this here because we don't execute OSIntCtxSw().  */
            return;
        }
    }
#endif

#if (OS_CFG_TASK_PROFILE_EN > 0u)
    OSTCBHighRdyPtr->CtxSwCtr++;                                /* Inc. # of context switches for this new task         */
#endif
#if ((OS_CFG_TASK_PROFILE_EN > 0u) || (OS_CFG_DBG_EN > 0u))
    OSTaskCtxSwCtr++;                                           /* Keep track of the total number of ctx switches       */
#endif

#if defined(OS_CFG_TLS_TBL_SIZE) && (OS_CFG_TLS_TBL_SIZE > 0u)
    OS_TLS_TaskSw();
#endif

    OS_TRACE_ISR_EXIT_TO_SCHEDULER();

    OSIntCtxSw();                                               /* Perform interrupt level ctx switch                   */

    CPU_INT_EN();
}


/*
** 2. ucosiii内核对任务优先级以及优先级对应就绪任务列表的实时更新维护。
** 2.1 对优先级的实时更新维护: OS_PrioInsert 函数  和 OS_PrioRemove 函数。
** 2.2 对就绪任务优先级对应的链表,即任务就绪列表,的实时更新维护: OS_RdyListInsert 函数  和  OS_RdyListRemove 函数。
*/  

/*
************************************************************************************************************************
*                                                  INSERT PRIORITY
*
* Description: This function is called to insert a priority in the priority table.
*
* Arguments  : prio     is the priority to insert
*
* Returns    : none
*
* Note(s)    : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
************************************************************************************************************************
*/

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
}


/*
************************************************************************************************************************
*                                                   REMOVE PRIORITY
*
* Description: This function is called to remove a priority in the priority table.
*
* Arguments  : prio     is the priority to remove
*
* Returns    : none
*
* Note(s)    : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
************************************************************************************************************************
*/

void  OS_PrioRemove (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
}




/*
************************************************************************************************************************
*                                             INSERT TCB IN THE READY LIST
*
* Description: This function is called to insert a TCB in the ready list.
*
*              The TCB is inserted at the tail of the list if the priority of the TCB is the same as the priority of the
*              current task.  The TCB is inserted at the head of the list if not.
*
* Arguments  : p_tcb     is a pointer to the TCB to insert into the ready list
*              -----
*
* Returns    : none
*
* Note(s)    : This function is INTERNAL to uC/OS-III and your application should not call it.
************************************************************************************************************************
*/

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



/*
************************************************************************************************************************
*                                REMOVE TCB FROM LIST KNOWING ONLY WHICH OS_TCB TO REMOVE
*
* Description: This function is called to remove an OS_TCB from an OS_RDY_LIST knowing the address of the OS_TCB to
*              remove.
*
*
*              CASE 0: TCB list is empty, nothing to do.
*
*              CASE 1: Only 1 OS_TCBs in the list.
*
*                     OS_RDY_LIST
*                     +--------------+          OS_TCB
*                     | TailPtr      |--+---> +------------+
*                     +--------------+  |     | NextPtr    |->0
*                     | HeadPtr      |--/     +------------+
*                     +--------------+     0<-| PrevPtr    |
*                     | NbrEntries=1 |        +------------+
*                     +--------------+        :            :
*                                             :            :
*                                             +------------+
*
*              CASE N: Two or more OS_TCBs in the list.
*
*                     OS_RDY_LIST
*                     +--------------+
*                     | TailPtr      |-----------------------------------------------+
*                     +--------------+          OS_TCB               OS_TCB          |     OS_TCB
*                     | HeadPtr      |------> +------------+       +------------+    +-> +------------+
*                     +--------------+        | NextPtr    |------>| NextPtr    | ...... | NextPtr    |->0
*                     | NbrEntries=N |        +------------+       +------------+        +------------+
*                     +--------------+     0<-| PrevPtr    |<------| PrevPtr    | ...... | PrevPtr    |
*                                             +------------+       +------------+        +------------+
*                                             :            :       :            :        :            :
*                                             :            :       :            :        :            :
*                                             +------------+       +------------+        +------------+
*
*
* Arguments  : p_tcb    is a pointer to the OS_TCB to remove
*              -----
*
* Returns    : A pointer to the OS_RDY_LIST where the OS_TCB was
*
* Note(s)    : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
************************************************************************************************************************
*/

void  OS_RdyListRemove (OS_TCB  *p_tcb)
{
    OS_RDY_LIST  *p_rdy_list;
    OS_TCB       *p_tcb1;
    OS_TCB       *p_tcb2;



    p_rdy_list = &OSRdyList[p_tcb->Prio];
    p_tcb1     = p_tcb->PrevPtr;                                /* Point to next and previous OS_TCB in the list        */
    p_tcb2     = p_tcb->NextPtr;
    if (p_tcb1 == (OS_TCB *)0) {                                /* Was the OS_TCB to remove at the head?                */
        if (p_tcb2 == (OS_TCB *)0) {                            /* Yes, was it the only OS_TCB?                         */
#if (OS_CFG_DBG_EN > 0u)
            p_rdy_list->NbrEntries =           0u;              /* Yes, no more entries                                 */
#endif
            p_rdy_list->HeadPtr    = (OS_TCB *)0;
            p_rdy_list->TailPtr    = (OS_TCB *)0;
            OS_PrioRemove(p_tcb->Prio);
        } else {
#if (OS_CFG_DBG_EN > 0u)
            p_rdy_list->NbrEntries--;                           /* No,  one less entry                                  */
#endif
            p_tcb2->PrevPtr     = (OS_TCB *)0;                  /* adjust back link of new list head                    */
            p_rdy_list->HeadPtr =  p_tcb2;                      /* adjust OS_RDY_LIST's new head                        */
        }
    } else {
#if (OS_CFG_DBG_EN > 0u)
        p_rdy_list->NbrEntries--;                               /* No,  one less entry                                  */
#endif
        p_tcb1->NextPtr = p_tcb2;
        if (p_tcb2 == (OS_TCB *)0) {
            p_rdy_list->TailPtr = p_tcb1;                       /* Removing the TCB at the tail, adj the tail ptr       */
        } else {
            p_tcb2->PrevPtr     = p_tcb1;
        }
    }
    p_tcb->PrevPtr = (OS_TCB *)0;
    p_tcb->NextPtr = (OS_TCB *)0;

    OS_TRACE_TASK_SUSPENDED(p_tcb);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值