uC/OS-II源码分析(四)

简介: 内核结构1,  临界区,OS_ENTER_CRITICAL和OS_EXIT_CRITICAL为了处理临界区代码,必须关中断,等处理完毕后,再开中断。关中断可以避免其他任务或中断进入临界区代码。uC/OS-II定义了这两个宏来实现,但注意一条:调用uC/OS-II功能函数时,中断应该总是开着的。

内核结构

1,  临界区,OS_ENTER_CRITICAL和OS_EXIT_CRITICAL

为了处理临界区代码,必须关中断,等处理完毕后,再开中断。关中断可以避免其他任务或中断进入临界区代码。uC/OS-II定义了这两个宏来实现,但注意一条:调用uC/OS-II功能函数时,中断应该总是开着的。

      1)当OS_CRITICAL_METHOD= = 1时,简单实现如下:

 

    #define OS_ENTER_CRITICAL() disable_int() 
    # define OS_EXIT_CRITICAL() enable_int()

 

但这样有一个问题,如果禁止中断的情况下调用uC/OS-II功能函数,那么从功能函数返回时,中断可能变成允许的了,而实际上还是希望是禁止的。

      2)当OS_CRITICAL_METHOD= = 2时,实现如下:

    #define OS_ENTER_CRITICAL()    
            asm(“PUSH PSW”);
            asm(“DI”);
    #define OS_EXIT_CRITICAL()
            asm(“POP PSW”);

 

执行OS_ENTER_CRITICAL()时,先将中断状态保存到堆栈,然后关中断;执行OS_EXIT_CRITICAL()时,再从堆栈中恢复原来的中断开/关状态。这种方法不会改变中断状态,避免前面的问题。

      3)当OS_CRITICAL_METHOD= = 3时,实现如下:

    #define OS_ENTER_CRITICAL()    
        cpu_sr = get_processor_psw();
        disable_interrupts();
    #define OS_EXIT_CRITICAL()
        set_ processor_psw(cpu_sr);

 

      将处理器状态字保存在局部变量中。

2,  任务是一个无限循环,返回类型为void,参数void*,用于传数据给任务。任务可以调用OSTaskDel(OS_PRIO_SELF)进行自我删除。任务有5种状态:

1)     睡眠态。任务驻留在程序空间(ROM或RAM),还未交给uC/OS-II来管理。

2)     就绪态。OSTaskCreate()或OSTaskCreateExt()来创建一个任务后,就进入就绪态。任务可以调用OSTaskDel返回到睡眠态,或调用该函数让另一个任务进入睡眠态。

3)     运行态。OSStart()启动多任务运行。它只在启动时调用一次,运行就绪列表中优先级最高的任务。就绪的任务只有当所以优先级比其高的任务转为等待状态,或者是被删除了,才能进入运行态。

4)     等待状态。正在运行的任务可以调用OSTimeDly()或OSTimeDlyHMSM()将自身延迟一段时间进入等待状态,一直到延迟时间到来。这两个函数会强制执行任务切换,选择下一个优先级最高的任务运行。等待时间过去后,系统服务函数OSTimeTick()使延迟了的任务进入就绪态。

正在运行的任务也可能需要等待某一事件的发生,可以调用:OSFlagPend(),OSSemPend(),OSMutexPend(),OSMboxPend(),OSQPend()等函数。若某事件未发生,则任务进入等待状态,直到事件发生。当任务因等待事件被挂起时,下一个优先级最高的任务得到CPU。当事件发生了或超时,被挂起的任务进入就绪态。事件发生的报告可能来自另一个任务或中断服务子程序。

5)     中断服务态 。被中断的任务进入中断服务态,从而被挂起,中断服务子程序得到CPU,后者可能报告一个或多个事件发生,从而使一个或多个任务进入就绪态。因此从中断服务子程序返回前,uC/OS-II要判断被中断的任务的优先级和就绪列表中其他任务的优先级高低,选择最高的任务进入运行态。

6)     当所以任务都在等待事件发生或等待延迟的时间结束时,uC/OS-II运行OSTaskIdle()任务。

3,  任务控制块(OS_TCB)

建立一个任务时,一个OS_TCB就被赋值。当任务的CPU被剥夺时,用它来保存任务的状态,当任务重新得到CPU时,它也能保证任务从当时被中断的那一点继续执行。OS_TCB全部驻留在RAM中。

 

typedef struct os_tcb 
{
    OS_STK        *OSTCBStkPtr;        /*指向当前任务堆栈栈顶的指针*/
#if OS_TASK_CREATE_EXT_EN > 0
    void          *OSTCBExtPtr;        /* 指向用户定义的任务控制块扩展*/
    OS_STK        *OSTCBStkBottom;     /* 指向栈底的指针*/
    INT32U         OSTCBStkSize;       /* 栈中可容纳的元素数目(
uC/OS-II允许每个任务的堆栈容量任意,)*/
    INT16U         OSTCBOpt;           /* 传给OSTaskCreateExt()的任务选择项*/
    INT16U         OSTCBId;            /* Task ID (0..65535) */
#endif
    struct os_tcb *OSTCBNext;          /*TCB列表中指向下一个TCB的指针*/
    struct os_tcb *OSTCBPrev;          /* TCB列表中指向上一个TCB的指针*/
#if ((OS_Q_EN > 0) && (OS_MAX_QS > 0)) || (OS_MBOX_EN > 0) || (OS_SEM_EN > 0) || (OS_MUTEX_EN > 0)
    OS_EVENT      *OSTCBEventPtr;      /*指向事件控制块的指针*/
#endif
#if ((OS_Q_EN > 0) && (OS_MAX_QS > 0)) || (OS_MBOX_EN > 0)
    void          *OSTCBMsg;           /*指向传递给任务的消息的指针,消息来自OSMboxPost() or OSQPost() */
#endif
#if (OS_VERSION >= 251) && (OS_FLAG_EN > 0) && (OS_MAX_FLAGS > 0)
#if OS_TASK_DEL_EN > 0
    OS_FLAG_NODE  *OSTCBFlagNode;      /*指向事件标志节点的指针*/
#endif    
    OS_FLAGS       OSTCBFlagsRdy;      /* 使任务进入就绪态的事件标志*/
#endif
    INT16U         OSTCBDly;           /* 让任务延时若干节拍或把任务挂起一段时间等待某一事件发生时使用的计时变量*/
    INT8U          OSTCBStat;          /* 任务状态*/
    INT8U          OSTCBPrio;          /* 任务优先级(0 == highest, 63 == lowest)*/
    //下面四个变量用于加速任务进入就绪态或进入等待事件发生状态的过程,算法比较巧妙
    INT8U          OSTCBX;             /* Bit position in group  corresponding to task priority (0..7) */
    INT8U          OSTCBY;             /* Index into ready table corresponding to task priority        
    INT8U          OSTCBBitX;          /* Bit mask to access bit position in ready table               
    INT8U          OSTCBBitY;          /* Bit mask to access bit position in ready group               
#if OS_TASK_DEL_EN > 0
    BOOLEAN        OSTCBDelReq;        /* 表面任务是否需要删除自己*/
#endif
} OS_TCB;

 

uC/OS-II在通过OS_MAX_TASKS定义了最大的任务数目,这也决定了分配给用户程序的任务控制块OS_TCB的数目,但此外uC/OS-II还分配给系统任务OS_N_SYS_TASKS若干个额外的任务控制块,供其内部使用。uC/OS-II初始化时,所以任务控制块都被链接成单向空任务链表,任务一旦建立,空任务控制块指针OSTCBFreeList指向的任务控制块就赋给该任务,然后OSTCBFreeList调整为指向链表中下一个空任务控制块。一旦任务被删除,任务控制块被还给空任务链表。

      任务建立时,OS_TCBInit()初始化任务控制块,函数OSTaskCreate()或OSTaskCreateExt()调用任务控制块初始化函数TCBInit。

 

INT8U  OS_TCBInit (INT8U prio, OS_STK *ptos, OS_STK *pbos, INT16U id, INT32U stk_size, void *pext, INT16U opt)
{
#if OS_CRITICAL_METHOD == 3                                /* 为CPU状态寄存器分配内存*/
    OS_CPU_SR  cpu_sr;
#endif    
    OS_TCB    *ptcb;
    OS_ENTER_CRITICAL();
    ptcb = OSTCBFreeList;                                  /* 从空闲TCB链表中取一个空TCB*/
    if (ptcb != (OS_TCB *)0) 
    {//取到了空TCB
        OSTCBFreeList        = ptcb->OSTCBNext;            /* 更新空闲TCB链表头指针*/
        OS_EXIT_CRITICAL();
        ptcb->OSTCBStkPtr    = ptos;                       /* 保存栈顶指针到TCB*/
        ptcb->OSTCBPrio      = (INT8U)prio;                /* 保存任务优先级到TCB*/
        ptcb->OSTCBStat      = OS_STAT_RDY;                /* 任务状态设置为就绪*/
        ptcb->OSTCBDly       = 0;                          /* 任务不延时等待*/
#if OS_TASK_CREATE_EXT_EN > 0//使用扩展
        ptcb->OSTCBExtPtr    = pext;                       /* 保存TCB扩展指针*/
        ptcb->OSTCBStkSize   = stk_size;                   /* 保存栈大小*/
        ptcb->OSTCBStkBottom = pbos;                       /* 保存栈底*/
        ptcb->OSTCBOpt       = opt;                        /* 保存任务选择项*/
        ptcb->OSTCBId        = id;                         /*保存任务ID*/
#else//不使用扩展
        pext                 = pext;                       
        stk_size             = stk_size;
        pbos                 = pbos;
        opt                  = opt;
        id                   = id;
#endif
#if OS_TASK_DEL_EN > 0
        ptcb->OSTCBDelReq    = OS_NO_ERR;                //初始化删除标志
#endif
        ptcb->OSTCBY         = prio >> 3;                  /* 预先计算X, Y, BitX and BitY*/
        ptcb->OSTCBBitY      = OSMapTbl[ptcb->OSTCBY];
        ptcb->OSTCBX         = prio & 0x07;
        ptcb->OSTCBBitX      = OSMapTbl[ptcb->OSTCBX];

#if OS_EVENT_EN > 0
        ptcb->OSTCBEventPtr  = (OS_EVENT *)0;              /* 任务不等待任何事件发生*/
#endif
#if (OS_VERSION >= 251) && (OS_FLAG_EN > 0) && (OS_MAX_FLAGS > 0) && (OS_TASK_DEL_EN > 0)
        ptcb->OSTCBFlagNode  = (OS_FLAG_NODE *)0;          /* 任务不等待事件标志*/
#endif
#if (OS_MBOX_EN > 0) || ((OS_Q_EN > 0) && (OS_MAX_QS > 0))
        ptcb->OSTCBMsg       = (void *)0;                  /* 没有接收任何消息*/
#endif
#if OS_VERSION >= 204
        OSTCBInitHook(ptcb);
#endif
        OSTaskCreateHook(ptcb);                            /* 调用用户定义的钩子函数*/
        OS_ENTER_CRITICAL();
        OSTCBPrioTbl[prio] = ptcb;
        ptcb->OSTCBNext    = OSTCBList;                    /*将TCB插入已经建立任务的双向链表中*/
        ptcb->OSTCBPrev    = (OS_TCB *)0;
        if (OSTCBList != (OS_TCB *)0) {
            OSTCBList->OSTCBPrev = ptcb;
        }
        OSTCBList               = ptcb;
        OSRdyGrp               |= ptcb->OSTCBBitY;         /*让用户进入就绪态*/
        OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
        OS_EXIT_CRITICAL();
        return (OS_NO_ERR);
    }
    OS_EXIT_CRITICAL();
    return (OS_NO_MORE_TCB);
}

 

作者:洞庭散人

出处:http://phinecos.cnblogs.com/    

本博客遵从 Creative Commons Attribution 3.0 License,若用于非商业目的,您可以自由转载,但请保留原作者信息和文章链接URL。
目录
相关文章
|
1月前
|
移动开发 监控 小程序
mPaaS 常见问题之Android 14uc内核不生效如何解决
mPaaS(移动平台即服务,Mobile Platform as a Service)是阿里巴巴集团提供的一套移动开发解决方案,它包含了一系列移动开发、测试、监控和运营的工具和服务。以下是mPaaS常见问题的汇总,旨在帮助开发者和企业用户解决在使用mPaaS产品过程中遇到的各种挑战
17 0
|
1月前
|
Web App开发 JSON 移动开发
mPaaS常见问题之加载不到uc 内核如何解决
mPaaS(移动平台即服务,Mobile Platform as a Service)是阿里巴巴集团提供的一套移动开发解决方案,它包含了一系列移动开发、测试、监控和运营的工具和服务。以下是mPaaS常见问题的汇总,旨在帮助开发者和企业用户解决在使用mPaaS产品过程中遇到的各种挑战
22 0
|
存储 缓存 Go
iOS原理分析之从源码看load与initialize方法(一)
iOS原理分析之从源码看load与initialize方法
210 0
iOS原理分析之从源码看load与initialize方法(一)
|
Web App开发
uC/OS-II源码分析(四)
内核结构 1,  临界区,OS_ENTER_CRITICAL和OS_EXIT_CRITICAL 为了处理临界区代码,必须关中断,等处理完毕后,再开中断。关中断可以避免其他任务或中断进入临界区代码。uC/OS-II定义了这两个宏来实现,但注意一条:调用uC/OS-II功能函数时,中断应该总是开着的。
944 0
|
Web App开发 消息中间件 存储
uC/OS-II源码分析(二)
在真正开始分析源代码前,先来看使用uC/OS-II的三个例子 1)使用信号量   #define  TASK_STK_SIZE                 512       /* 每个任务堆栈的大小(以字计算)*/#define  N_TASKS                        ...
1633 0
|
Web App开发 调度 消息中间件
uC/OS-II源码分析(一)
下载地址:http://www.micrium.com/ 它的特点: 1)开源, 2)可移植性,绝大部分代码用C写,硬件相关部分用汇编写, 3可固化, 4)可剪裁,这通过条件编译实现,使用#define语句定义所需要的功能。
904 0
|
Web App开发 调度 消息中间件
uC/OS-II源码分析(三)
首先来了解下实时系统的基本概念: 1) 临界区,共享资源,任务(类似于进程),任务切换,任务调度,可剥夺型内核,可重入函数,动态优先级调度, 2) 如何处理优先级反转问题。这个问题描述如下:有三个任务,优先级1高于2,2高于3,一开始1和2处于挂起,3在运行,3要使用某个共享资源,就P它的互斥信号量,3得到信号量后开始使用这个共享资源。
810 0
|
Web App开发 调度
uC/OS-II源码分析(五)
每个任务被赋予不同的优先级等级,从0 级到最低优先级OS_LOWEST_PR1O,包括0 和 OS_LOWEST_PR1O 在内。当μC/OS-Ⅱ初始化的时候,最低优先级OS_LOWEST_PR1O 总是被赋给空闲任务idle task 。
711 0
|
Web App开发 调度 消息中间件
uC/OS-II源码分析(六)
μC/OS-Ⅱ总是运行进入就绪态任务中优先级最高的那一个。确定哪个任务优先级最高, 下面该哪个任务运行了的工作是由调度器(Scheduler)完成的。任务级的调度是由函数 OSSched()完成的。中断级的调度是由另一个函数OSIntExt() 完成的,这个函数将在以后描 述。
861 0