嵌入式内核分析

来源:互联网 发布:win7系统优化设置 编辑:程序博客网 时间:2024/06/06 03:32

嵌入式内核分析
    --内核就是我,我就是内核


第一篇  uC/OSII
    第一章  内核
    第二章  任务管理
    第三章  中断和时间
    第四章  事件控制块
    第五章  信号量管理
    第六章  互斥信号量管理
    第七章  事件标志组管理
    第八章  消息邮箱管理
    第九章  消息队列管理
    第十章  内存管理

 

第一章  内核
   
    一  临界段
        关中断的时间是实时内核开发商提供的最重要的指标之一。
        uC/OSII定义两个宏来关中断和开中断。分别是OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()。
        有三种不同的方法,见OS_CPU.H中的OS_CRITICAL_METHOD
        1  OS_CRITICAL_METHOD==1
           最简单方式处理,用处理器指令关中断,用开中断退出
        2  OS_CRITICAL_METHOD==2
           #define OS_ENTER_CRITICAL()
              asm("PUSH PSW")
              asm("DI")
           #define OS_EXIT_CRITICAL()
              asm("POP PSW")
        3  OS_CRITICAL_METHOD==3
           #define OS_ENTER_CRITICAL()
              cpu_sr = get_processer_psw();
              disable_interrupts();
           #define OS_EXIT_CRITICAL
              set_processor_psw(cpu_sr);


    二  任务状态
        五种状态: 睡眠态、就绪态、运行态、等待状态、中断服务态
        1  睡眠态 task dormant
           指任务驻留在程序空间,还没有交给操作系统管理,交给操作系统是通过OSTaskCreate()或OSTaskCreateExt()来实现。
        2  就绪态
           任务一旦建立,就进入就绪态,准备运行。一个任务可以通过OSTaskDel()返回到睡眠态。
        3  运行态
           调用OSStart()可以启动多任务。该函数运行用户初始化代码中已经建立的、进入就绪态的优秀级最高的任务。
           任何时候只有一个任务处于运行态。
           就绪的任务只有当所有优先级高于这个任务的任务都转为等待状态,或者是被删除了,才能进入运行态。
        4  等待状态
           正在运行的任务可以通过调用以下2个函数之一,将自身延迟一段时间,这2个函数是OSTimeDly()或OSTimeDlyHMSM()。
           正在运行的任务可能需要等待某一个事件的发生,可以通过调用一下函数之一实现:
           OSFlagPend(),OSSemPend(),OSMutexPend(),OSMboxPend(),OSQPend()
           当事件发生了或等待超时时,被挂起的任务就进入就绪态
           调用延时函数后,会立刻强制执行任务切换,让下一个优先级最高的、并进入了就绪态的任务运行。
        5  中断服务态
           正在运行的任务是可以被中断的,被中断的任务于是进入了中断服务态(ISR running)。
          

     三  任务控制块
         任务控制块是一个数据结构,当任务的CPU使用权被剥夺时,uC/OS-II用它来保存该任务的状态。
typedef struct os_tcb {
    OS_STK          *OSTCBStkPtr;           /* Pointer to current top of stack                         */

#if OS_TASK_CREATE_EXT_EN > 0
    void            *OSTCBExtPtr;           /* Pointer to user definable data for TCB extension        */
    OS_STK          *OSTCBStkBottom;        /* Pointer to bottom of stack                              */
    INT32U           OSTCBStkSize;          /* Size of task stack (in number of stack elements)        */
    INT16U           OSTCBOpt;              /* Task options as passed by OSTaskCreateExt()             */
    INT16U           OSTCBId;               /* Task ID (0..65535)                                      */
#endif

    struct os_tcb   *OSTCBNext;             /* Pointer to next     TCB in the TCB list                 */
    struct os_tcb   *OSTCBPrev;             /* Pointer to previous TCB in the TCB list                 */

#if (OS_EVENT_EN) || (OS_FLAG_EN > 0)
    OS_EVENT        *OSTCBEventPtr;         /* Pointer to          event control block                 */
#endif

#if (OS_EVENT_EN) && (OS_EVENT_MULTI_EN > 0)
    OS_EVENT       **OSTCBEventMultiPtr;    /* Pointer to multiple event control blocks                */
#endif

#if ((OS_Q_EN > 0) && (OS_MAX_QS > 0)) || (OS_MBOX_EN > 0)
    void            *OSTCBMsg;              /* Message received from OSMboxPost() or OSQPost()         */
#endif

#if (OS_FLAG_EN > 0) && (OS_MAX_FLAGS > 0)
#if OS_TASK_DEL_EN > 0
    OS_FLAG_NODE    *OSTCBFlagNode;         /* Pointer to event flag node                              */
#endif
    OS_FLAGS         OSTCBFlagsRdy;         /* Event flags that made task ready to run                 */
#endif

    INT16U           OSTCBDly;              /* Nbr ticks to delay task or, timeout waiting for event   */
    INT8U            OSTCBStat;             /* Task      status                                        */
    INT8U            OSTCBStatPend;         /* Task PEND status                                        */
    INT8U            OSTCBPrio;             /* Task priority (0 == highest)                            */

    INT8U            OSTCBX;                /* Bit position in group  corresponding to task priority   */
    INT8U            OSTCBY;                /* Index into ready table corresponding to task priority   */
#if OS_LOWEST_PRIO <= 63
    INT8U            OSTCBBitX;             /* Bit mask to access bit position in ready table          */
    INT8U            OSTCBBitY;             /* Bit mask to access bit position in ready group          */
#else
    INT16U           OSTCBBitX;             /* Bit mask to access bit position in ready table          */
    INT16U           OSTCBBitY;             /* Bit mask to access bit position in ready group          */
#endif

#if OS_TASK_DEL_EN > 0
    INT8U            OSTCBDelReq;           /* Indicates whether a task needs to delete itself         */
#endif

#if OS_TASK_PROFILE_EN > 0
    INT32U           OSTCBCtxSwCtr;         /* Number of time the task was switched in                 */
    INT32U           OSTCBCyclesTot;        /* Total number of clock cycles the task has been running  */
    INT32U           OSTCBCyclesStart;      /* Snapshot of cycle counter at start of task resumption   */
    OS_STK          *OSTCBStkBase;          /* Pointer to the beginning of the task stack              */
    INT32U           OSTCBStkUsed;          /* Number of bytes used from the stack                     */
#endif

#if OS_TASK_NAME_SIZE > 1
    INT8U            OSTCBTaskName[OS_TASK_NAME_SIZE];
#endif
} OS_TCB;

    参数的意义
    1   OSTCBStkPtr 指向当前任务堆栈栈顶的指针。
    2   OSTCBExtPtr 指向用户定义的任务控制块扩展。
    3   OSTCBStkBottom 指向任务堆栈栈底的指针。
    4   OSTCBStkSize 存有栈中可容纳的指针元数目。
    5   OSTCBOpt 把“选择项”传给函数OSTaskCreateExt()。
    6   OSTCBId 用于存储任务的识别码,目前没用保留。
    7   OSTCBNext、OSTCBPrev 用于任务控制块OS_TCB双向链表的前/后链接。
    8   OSTCBEventPtr 指向事件控制块的指针。
    9   OSTCBMsg 指向传递给任务的消息的指针。
    10  OSTCBFlagNode 指向事件标志节点的指针。
    11  OSTCBFlagsRdy 当任务等待事件标志组时,OSTCBFlagsRdy是使任务进入就绪态的事件标志。
    12  OSTCBDly 当需要把任务延时若干时钟节拍,或者需要把任务挂起一段事件以等待某事件的发生时,需用到这个变量。
    13  OSTCBStat 任务的状态字
    14  OSTCBPrio 任务的优先级
    15  OSTCBX、OSTCBY、OSTCBBitX、OSTCBBitY 用于加速任务进入就绪态的过程或进入等待事件发生状态的过程。
    16  OSTCBDelReq 一个布尔量,用于表示该任务是否须删除。

INT8U  OS_TCBInit (INT8U prio, OS_STK *ptos, OS_STK *pbos, INT16U id, INT32U stk_size, void *pext, INT16U opt)
{
    OS_TCB    *ptcb;
#if OS_CRITICAL_METHOD == 3                                /* Allocate storage for CPU status register */
    OS_CPU_SR  cpu_sr = 0;
#endif

 

    OS_ENTER_CRITICAL();   // 1
    ptcb = OSTCBFreeList;                                  /* Get a free TCB from the free TCB list    */
    if (ptcb != (OS_TCB *)0) {   // 2
        OSTCBFreeList            = ptcb->OSTCBNext;        /* Update pointer to free TCB list          */
        OS_EXIT_CRITICAL();
        ptcb->OSTCBStkPtr        = ptos;       // 3            /* Load Stack pointer in TCB                */
        ptcb->OSTCBPrio          = prio;                   /* Load task priority into TCB              */
        ptcb->OSTCBStat          = OS_STAT_RDY;            /* Task is ready to run                     */
        ptcb->OSTCBStatPend      = OS_STAT_PEND_OK;        /* Clear pend status                        */
        ptcb->OSTCBDly           = 0;                      /* Task is not delayed                      */

#if OS_TASK_CREATE_EXT_EN > 0
        ptcb->OSTCBExtPtr        = pext;      // 4             /* Store pointer to TCB extension           */
        ptcb->OSTCBStkSize       = stk_size;               /* Store stack size                         */
        ptcb->OSTCBStkBottom     = pbos;                   /* Store pointer to bottom of stack         */
        ptcb->OSTCBOpt           = opt;                    /* Store task options                       */
        ptcb->OSTCBId            = id;                     /* Store task ID                            */
#else
        pext                     = pext;                   /* Prevent compiler warning if not used     */
        stk_size                 = stk_size;
        pbos                     = pbos;
        opt                      = opt;
        id                       = id;
#endif

#if OS_TASK_DEL_EN > 0
        ptcb->OSTCBDelReq        = OS_ERR_NONE;  //5
#endif

#if OS_LOWEST_PRIO <= 63
        ptcb->OSTCBY             = (INT8U)(prio >> 3);   // 6       /* Pre-compute X, Y, BitX and BitY     */
        ptcb->OSTCBX             = (INT8U)(prio & 0x07);
        ptcb->OSTCBBitY          = (INT8U)(1 << ptcb->OSTCBY);
        ptcb->OSTCBBitX          = (INT8U)(1 << ptcb->OSTCBX);
#else
        ptcb->OSTCBY             = (INT8U)((prio >> 4) & 0xFF); /* Pre-compute X, Y, BitX and BitY     */
        ptcb->OSTCBX             = (INT8U) (prio & 0x0F);
        ptcb->OSTCBBitY          = (INT16U)(1 << ptcb->OSTCBY);
        ptcb->OSTCBBitX          = (INT16U)(1 << ptcb->OSTCBX);
#endif

#if (OS_EVENT_EN)
        ptcb->OSTCBEventPtr      = (OS_EVENT  *)0;     // 7     /* Task is not pending on an  event         */
#if (OS_EVENT_MULTI_EN > 0)
        ptcb->OSTCBEventMultiPtr = (OS_EVENT **)0;         /* Task is not pending on any events        */
#endif
#endif

#if (OS_FLAG_EN > 0) && (OS_MAX_FLAGS > 0) && (OS_TASK_DEL_EN > 0)
        ptcb->OSTCBFlagNode  = (OS_FLAG_NODE *)0;   // 8       /* Task is not pending on an event flag     */
#endif

#if (OS_MBOX_EN > 0) || ((OS_Q_EN > 0) && (OS_MAX_QS > 0))
        ptcb->OSTCBMsg       = (void *)0;                  /* No message received                      */
#endif

#if OS_TASK_PROFILE_EN > 0
        ptcb->OSTCBCtxSwCtr    = 0L;                       /* Initialize profiling variables           */
        ptcb->OSTCBCyclesStart = 0L;
        ptcb->OSTCBCyclesTot   = 0L;
        ptcb->OSTCBStkBase     = (OS_STK *)0;
        ptcb->OSTCBStkUsed     = 0L;
#endif

#if OS_TASK_NAME_SIZE > 1
        ptcb->OSTCBTaskName[0] = '?';                      /* Unknown name at task creation            */
        ptcb->OSTCBTaskName[1] = OS_ASCII_NUL;
#endif

        OSTCBInitHook(ptcb);  //9

        OSTaskCreateHook(ptcb);            // 10                /* Call user defined hook                   */

        OS_ENTER_CRITICAL();            // 11
        OSTCBPrioTbl[prio] = ptcb;  // 12
        ptcb->OSTCBNext    = OSTCBList;                    /* Link into TCB chain                      */
        ptcb->OSTCBPrev    = (OS_TCB *)0;
        if (OSTCBList != (OS_TCB *)0) {
            OSTCBList->OSTCBPrev = ptcb;
        }
        OSTCBList               = ptcb;
        OSRdyGrp               |= ptcb->OSTCBBitY;     // 13    /* Make task ready to run                   */
        OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
        OSTaskCtr++;                                       /* Increment the #tasks counter             */
        OS_EXIT_CRITICAL();
        return (OS_ERR_NONE);  // 14
    }
    OS_EXIT_CRITICAL();
    return (OS_ERR_TASK_NO_MORE_TCB);

     (1、2) 首先试图从OS_TCB缓冲池中得到一个任务控制块
     (3)  如果缓冲池中有空余的OS_TCB,就被初始化了
     (4)  额外的变元就插入到OS_TCB中了
     (5)  OS_TCB中是否出现OSTCBDelReq取决于OS_TASK_DEL_EN是否被置1
     (6)  以存储空间换取执行时间
     (7)  不打算使用信号量等
     (8)  初始化为空指针
     (9)  增加了对函数OSTCBInitHook()的调用
     (10) OS_TCBInit()然后调用OSTaskCreateHook()
     (12) 关中断
     (14) 最后,让任务进入就绪态


      四、 就绪表
           每个就绪的任务都放在就绪表中,就绪表中有两个变量,OSRdyGrp和OSRdyTbl[]
           它们的关系是: 当OSRdyTbl[i]中的任何一位是1时,OSRdyGrp的第i位置1

      五、 任务调度
           确定那个任务优先级最高,下面该那个任务运行了,这一工作是有调度器完成的。

void  OS_Sched (void)
{
#if OS_CRITICAL_METHOD == 3                            /* Allocate storage for CPU status register     */
    OS_CPU_SR  cpu_sr = 0;
#endif

 

    OS_ENTER_CRITICAL();
    if (OSIntNesting == 0) {                           /* Schedule only if all ISRs done and ...       */
        if (OSLockNesting == 0) {         // 1             /* ... scheduler is not locked                  */
            OS_SchedNew();
            if (OSPrioHighRdy != OSPrioCur) {   // 3        /* No Ctx Sw if current task is highest rdy     */
                OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];  // 4
#if OS_TASK_PROFILE_EN > 0
                OSTCBHighRdy->OSTCBCtxSwCtr++;         /* Inc. # of context switches to this task      */
#endif
                OSCtxSwCtr++;         // 5                 /* Increment context switch counter             */
                OS_TASK_SW();         // 6                 /* Perform a context switch                     */
            }
        }
    }
    OS_EXIT_CRITICAL();
}
    1  如果调用来自中断服务子程序,或者由于至少调用了一次给任务调度上锁函数,任务调度函数将退出,不做调度任务
    3  找到优先级最高的任务后,校验这个优先级最高的任务是否是当前正在运行的任务,以避免不必要的任务调度
    4  为实现任务切换,OSTCBHighRdy必须指向优先级最高的任务控制块
    5  OSTCBCtxSwCtr加1,以跟踪任务切换次数
    6  最后,调用宏OS_TASK_SW,完成实际的任务切换


    六  给调度器上锁和开锁
        上锁用于禁止任务调度,直到任务完成后,调度给调度器开锁函数。
void  OSSchedLock (void)
{
#if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
    OS_CPU_SR  cpu_sr = 0;
#endif

 

    if (OSRunning == OS_TRUE) {    // 1             /* Make sure multitasking is running                  */
        OS_ENTER_CRITICAL();
        if (OSIntNesting == 0) {                 /* Can't call from an ISR                             */
            if (OSLockNesting < 255u) {      // 2      /* Prevent OSLockNesting from wrapping back to 0      */
                OSLockNesting++;                 /* Increment lock nesting level                       */
            }
        }
        OS_EXIT_CRITICAL();
    }
}
        1  如果多任务已经启动了,则给调度器上锁才有意义。
        2  在给嵌套层数加1之前,须确认嵌套层数没有超界。

void  OSSchedUnlock (void)
{
#if OS_CRITICAL_METHOD == 3                                /* Allocate storage for CPU status register */
    OS_CPU_SR  cpu_sr = 0;
#endif

 

    if (OSRunning == OS_TRUE) {                 // 1           /* Make sure multitasking is running        */
        OS_ENTER_CRITICAL();
        if (OSLockNesting > 0) {             // 2              /* Do not decrement if already 0            */
            OSLockNesting--;                     // 3          /* Decrement lock nesting level             */
            if (OSLockNesting == 0) {                      /* See if scheduler is enabled and ...      */
                if (OSIntNesting == 0) {          // 4           /* ... not in an ISR                        */
                    OS_EXIT_CRITICAL();
                    OS_Sched();             // 5               /* See if a HPT is ready                    */
                } else {
                    OS_EXIT_CRITICAL();
                }
            } else {
                OS_EXIT_CRITICAL();
            }
        } else {
            OS_EXIT_CRITICAL();
        }
    }
}

       
       1  如果多任务已经启动了,则给调度器开锁才有意义。
       2  确认OSLockNesting还没有回0
       3  OSLockNesting减1
      


     七  中断
        
         用户中断服务子程序
             保存全部CPU寄存器
             调用OSIntEnter()或OSIntNesting直接加1
             if(OSIntNesting==1) {
                OSTCBCur->OSTCBStkPtr=SP;
      }
             请中断源
             重新开中断
             执行用户代码做中断服务
             调用OSIntExit()
             恢复所有CPU寄存器
             执行中断返回指令

 

 

 

   


   


       

 

       
       

 

 

 

 

 

原创粉丝点击