μC/OS-II--任务

μC/OS-II最小资源分配单元是任务。

任务状态

μC/OS-II中任务有5种状态,分别为睡眠态,就绪态,运行态,就绪态,等待状态,中断服务态。睡眠态指任务还没有创建或者创建后被删除。就绪态是指任务准备运行,等待CPU使用权。运行态指获得CPU使用权,任务执行。等待状态是指正在运行的任务调用等待或延时函数时进入的状态。中断服务态是指运行态被打断,进入中断服务程序。

μC/OS-II--任务

任务控制块

任务控制块是一个数据结构,用于保存任务的参数和状态。

typedef struct os_tcb {
    //OS_STK定义为32位无符号数据,该行定义当前任务所分配的堆栈的栈顶指针
    //(该栈顶指针是指任务切换后自动保存的r0-r15等一系列数据后的堆栈指针)
    //对于堆栈,ucos可以对每一个任务分配任意大小的堆栈
    OS_STK          *OSTCBStkPtr;      /* Pointer to current top of stack                              */

#if OS_TASK_CREATE_EXT_EN > 0//如果使能了扩展任务控制块,则定义以下数据

    //扩展任务块的指针,扩展任务快的引入,使得可以在不改变ucos源码的情况下,
    //加入扩展功能,此外如果需要使用该功能,则需在OS_CFG.H(ucos配置文件)
    //中将OS_TASK_CREATE_EXT_EN 置1,允许建立任务函数扩展
    void            *OSTCBExtPtr;      /* Pointer to user definable data for TCB extension             */

    //指向任务堆栈的栈底(就是数据最后进入的地址),如果堆栈增长方式是递增的,那么他执向堆栈的最高地址
    //反之指向最低地址,该参数在使用OSTaskStkChk函数时需要调用
    OS_STK          *OSTCBStkBottom;   /* Pointer to bottom of stack  */
    
    //该参数是任务堆栈的大小,对于堆栈大小是指栈中所能容纳的指针数目,而不是字节数目,假设堆栈容量为1000,
    //如果地址宽度为32位,那么堆栈包含4000个字节。但是其容量是1000
    INT32U           OSTCBStkSize;     /* Size of task stack (in number of stack elements)             */

    //选择项,支持3种选择e:
    //OS_TASK_OPT_STK_CHK,该参数用于告知TaskCreateExt函数在建立任务时对堆栈进行检查(不定义这个ucos不会进行检查)
    //OS_TASK_OPT_STK_CLR,在任务建立 时将任务栈清零,至于在需要使用栈检验功能时才将栈清零
    //OS_TASK_OPT_SAVE_FP,通知任务需要做浮点运算
    INT16U           OSTCBOpt;         /* Task options as passed by OSTaskCreateExt()                  */

    //用于存储任务的识别码,现在还没使用,感觉他会发展成为linux的pid
    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_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

    //任务延时时间,或者等待事件发生的超时时间,在时钟每发生一次中断的时候,时钟街拍函数OSTimeTick
    //将通过任务控制块的链表访问该变量,并将其减1,刷新变量
    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)                                 */

    //表示任务就绪表中X轴的位置,相当于说明该优先级是某一组的哪一位元素
    INT8U            OSTCBX;           /* Bit position in group  corresponding to task priority        */

    //表示任务就绪表中Y轴的位置,相当于说明该优先级是哪一组的元素
    INT8U            OSTCBY;           /* Index into ready table corresponding to task priority        */


    
#if OS_LOWEST_PRIO <= 63
    //说明该优先级对应的OSTCBTBL[prio & 0x7]中元素赋值
    INT8U            OSTCBBitX;        /* Bit mask to access bit position in ready table               */
    //说明该优先级对应的OSRdyGrp的元素
    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;

关于任务还有几个全局变量

OS_EXT  OS_TCB           *OSTCBCur;                      //指向当前运行任务TCB的指针
OS_EXT  OS_TCB           *OSTCBFreeList;                 //执行下一个可用TCB指针
OS_EXT  OS_TCB           *OSTCBHighRdy;                  //指向最高优先级的TCB的指针
OS_EXT  OS_TCB           *OSTCBList;                     //指向所创建TCB链表的指针
OS_EXT  OS_TCB           *OSTCBPrioTbl[OS_LOWEST_PRIO + 1];//指向所创建TCB表的指针
OS_EXT  OS_TCB            OSTCBTbl[OS_MAX_TASKS + OS_N_SYS_TASKS];  //TCB表

在系统初始化时,默认在RAM中开辟OS_MAX_TASKS + OS_N_SYS_TASKS(最大允许创建的任务数+系统任务)大的0S_TCB类型的数组,此时结构如下所示:

μC/OS-II--任务

μC/OS-II--任务

创建系统任务后:

μC/OS-II--任务

μC/OS-II--任务

 

任务创建与删除

任务的创建通过OSTaskCreate或OSTaskCreateExt完成,任务删除通过OSTaskDel完成。

OSTaskCreate:

INT8U  OSTaskCreate(void (*task)(void *p_arg),void *p_arg,OS_STK *ptos,INT8U prio)
{
    OS_STK    *psp;
    INT8U      err;
#if OS_CRITICAL_METHOD == 3                  /* Allocate storage for CPU status register               */
    OS_CPU_SR  cpu_sr = 0;
#endif



#if OS_ARG_CHK_EN > 0
    if(prio > OS_LOWEST_PRIO)  /* Make sure priority is within allowable range           */
	  {            
        return (OS_ERR_PRIO_INVALID);
      }
#endif

    OS_ENTER_CRITICAL();    //保存全局中断标志,关中断

      if(OSIntNesting>0)      /* Make sure we don't create the task from within an ISR  */
	    {                  
         OS_EXIT_CRITICAL();	//恢复全局中断标志
         return (OS_ERR_TASK_CREATE_ISR);
        }

      if(OSTCBPrioTbl[prio]==(OS_TCB *)0)  /* Make sure task doesn't already exist at this priority  */
	     { 
           OSTCBPrioTbl[prio]=OS_TCB_RESERVED;/* Reserve the priority to prevent others from doing ...  */
                                              /* ... the same thing until task is created.              */
           OS_EXIT_CRITICAL();	//恢复全局中断标志
           psp = OSTaskStkInit(task,p_arg,ptos,0);              /* Initialize the task's stack         *///建立任务堆栈
           err = OS_TCBInit(prio,psp,(OS_STK *)0,0,0,(void *)0,0);//从空闲的OS_TCB池获得并初始化一个OS_TCB
           if(err == OS_ERR_NONE) 
		     {
               if(OSRunning==OS_TRUE) 
			     {      /* Find highest priority task if multitasking has started */
                   OS_Sched();//任务调度
                 }
             } 
		   else
		     {
               OS_ENTER_CRITICAL();  //保存全局中断标志,关中断
               OSTCBPrioTbl[prio] = (OS_TCB *)0;/* Make this priority available to others                 */
               OS_EXIT_CRITICAL();	  //恢复全局中断标志
             }
           return (err);
          }

    OS_EXIT_CRITICAL();	  //恢复全局中断标志
    return (OS_ERR_PRIO_EXIST);
}

OSTaskCreateExt:

INT8U  OSTaskCreate(void (*task)(void *p_arg),void *p_arg,OS_STK *ptos,INT8U prio)
{
    OS_STK    *psp;
    INT8U      err;
#if OS_CRITICAL_METHOD == 3                  /* Allocate storage for CPU status register               */
    OS_CPU_SR  cpu_sr = 0;
#endif



#if OS_ARG_CHK_EN > 0
    if(prio > OS_LOWEST_PRIO)  /* Make sure priority is within allowable range           */
	  {            
        return (OS_ERR_PRIO_INVALID);
      }
#endif

    OS_ENTER_CRITICAL();    //保存全局中断标志,关中断

      if(OSIntNesting>0)      /* Make sure we don't create the task from within an ISR  */
	    {                  
         OS_EXIT_CRITICAL();	//恢复全局中断标志
         return (OS_ERR_TASK_CREATE_ISR);
        }

      if(OSTCBPrioTbl[prio]==(OS_TCB *)0)  /* Make sure task doesn't already exist at this priority  */
	     { 
           OSTCBPrioTbl[prio]=OS_TCB_RESERVED;/* Reserve the priority to prevent others from doing ...  */
                                              /* ... the same thing until task is created.              */
           OS_EXIT_CRITICAL();	//恢复全局中断标志
           psp = OSTaskStkInit(task,p_arg,ptos,0);              /* Initialize the task's stack         *///建立任务堆栈
           err = OS_TCBInit(prio,psp,(OS_STK *)0,0,0,(void *)0,0);//从空闲的OS_TCB池获得并初始化一个OS_TCB
           if(err == OS_ERR_NONE) 
		     {
               if(OSRunning==OS_TRUE) 
			     {      /* Find highest priority task if multitasking has started */
                   OS_Sched();
                 }
             } 
		   else
		     {
               OS_ENTER_CRITICAL();  //保存全局中断标志,关中断
               OSTCBPrioTbl[prio] = (OS_TCB *)0;/* Make this priority available to others                 */
               OS_EXIT_CRITICAL();	  //恢复全局中断标志
             }
           return (err);
          }

    OS_EXIT_CRITICAL();	  //恢复全局中断标志
    return (OS_ERR_PRIO_EXIST);
}

OSTaskDel:

INT8U  OSTaskDel (INT8U prio)
{
#if OS_EVENT_EN
    OS_EVENT     *pevent;
#endif
#if (OS_FLAG_EN > 0) && (OS_MAX_FLAGS > 0)
    OS_FLAG_NODE *pnode;
#endif
    OS_TCB       *ptcb;
    INT8U         y;
#if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
    OS_CPU_SR     cpu_sr = 0;
#endif



    if (OSIntNesting > 0) {                                     /* See if trying to delete from ISR    */
        return (OS_ERR_TASK_DEL_ISR);
    }
    if (prio == OS_TASK_IDLE_PRIO) {                            /* Not allowed to delete idle task     */
        return (OS_ERR_TASK_DEL_IDLE);
    }
#if OS_ARG_CHK_EN > 0
    if (prio >= OS_LOWEST_PRIO) {                               /* Task priority valid ?               */
        if (prio != OS_PRIO_SELF) {
            return (OS_ERR_PRIO_INVALID);
        }
    }
#endif

    OS_ENTER_CRITICAL();
    if (prio == OS_PRIO_SELF) {                                 /* See if requesting to delete self    */
        prio = OSTCBCur->OSTCBPrio;                             /* Set priority to delete to current   */
    }
    ptcb = OSTCBPrioTbl[prio];
    if (ptcb == (OS_TCB *)0) {                                  /* Task to delete must exist           */
        OS_EXIT_CRITICAL();
        return (OS_ERR_TASK_NOT_EXIST);
    }
    if (ptcb == OS_TCB_RESERVED) {                              /* Must not be assigned to Mutex       */
        OS_EXIT_CRITICAL();
        return (OS_ERR_TASK_DEL);
    }
    y            =  ptcb->OSTCBY;
    OSRdyTbl[y] &= ~ptcb->OSTCBBitX;
    if (OSRdyTbl[y] == 0) {                                     /* Make task not ready                 */
        OSRdyGrp &= ~ptcb->OSTCBBitY;
    }
    
#if OS_EVENT_EN
    pevent = ptcb->OSTCBEventPtr;
    if (pevent != (OS_EVENT *)0) {                              /* If task is waiting on event         */
        pevent->OSEventTbl[y] &= ~ptcb->OSTCBBitX;
        if (pevent->OSEventTbl[y] == 0) {                       /* ... remove task from ...            */
            pevent->OSEventGrp &= ~ptcb->OSTCBBitY;             /* ... event ctrl block                */
        }
    }
#endif

#if (OS_FLAG_EN > 0) && (OS_MAX_FLAGS > 0)
    pnode = ptcb->OSTCBFlagNode;
    if (pnode != (OS_FLAG_NODE *)0) {                           /* If task is waiting on event flag    */
        OS_FlagUnlink(pnode);                                   /* Remove from wait list               */
    }
#endif

    ptcb->OSTCBDly      = 0;                                    /* Prevent OSTimeTick() from updating  */
    ptcb->OSTCBStat     = OS_STAT_RDY;                          /* Prevent task from being resumed     */
    ptcb->OSTCBStatPend = OS_STAT_PEND_OK;
    if (OSLockNesting < 255u) {                                 /* Make sure we don't context switch   */
        OSLockNesting++;
    }
    OS_EXIT_CRITICAL();                                         /* Enabling INT. ignores next instruc. */
    OS_Dummy();                                                 /* ... Dummy ensures that INTs will be */
    OS_ENTER_CRITICAL();                                        /* ... disabled HERE!                  */
    if (OSLockNesting > 0) {                                    /* Remove context switch lock          */
        OSLockNesting--;
    }
    OSTaskDelHook(ptcb);                                        /* Call user defined hook              */
    OSTaskCtr--;                                                /* One less task being managed         */
    OSTCBPrioTbl[prio] = (OS_TCB *)0;                           /* Clear old priority entry            */
    if (ptcb->OSTCBPrev == (OS_TCB *)0) {                       /* Remove from TCB chain               */
        ptcb->OSTCBNext->OSTCBPrev = (OS_TCB *)0;
        OSTCBList                  = ptcb->OSTCBNext;
    } else {
        ptcb->OSTCBPrev->OSTCBNext = ptcb->OSTCBNext;
        ptcb->OSTCBNext->OSTCBPrev = ptcb->OSTCBPrev;
    }
    ptcb->OSTCBNext   = OSTCBFreeList;                          /* Return TCB to free TCB list         */
    OSTCBFreeList     = ptcb;
#if OS_TASK_NAME_SIZE > 1
    ptcb->OSTCBTaskName[0] = '?';                               /* Unknown name                        */
    ptcb->OSTCBTaskName[1] = OS_ASCII_NUL;
#endif
    OS_EXIT_CRITICAL();
    if (OSRunning == OS_TRUE) {
        OS_Sched();                                             /* Find new highest priority task      */
    }
    return (OS_ERR_NONE);
}

空闲任务与统计任务

空闲任务和统计任务为系统任务。空闲任务为最低优先级OS_LOWEST_PRIO,在没有其他任务就绪时运行,不运行时永远处于就绪态。统计任务优先级为OS_LOWEST_PRIO - 1,可计算CPU利用率.

 

任务调度

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)   /* ... scheduler is not locked */
		  {                     
            OS_SchedNew(); //计算就绪任务里优先级最高的优先级,结果保存在OSPrioHighRdy里
            if(OSPrioHighRdy!=OSPrioCur)   /* No Ctx Sw if current task is highest rdy  */
			   {         
                 OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
                 #if OS_TASK_PROFILE_EN > 0
                    OSTCBHighRdy->OSTCBCtxSwCtr++;         /* Inc. # of context switches to this task */
                 #endif
                 OSCtxSwCtr++;   /* Increment context switch counter */
                 OS_TASK_SW();   //悬起PSV异常   /* Perform a context switch */
               }
           }
       }
     OS_EXIT_CRITICAL(); //恢复全局中断标志
}

 

上一篇:Codeforces Round #762 (Div. 3), CDE


下一篇:前端丨如何使用 tcb-js-sdk 实现图片上传功能