ostaskdel函数_cursor函数

ostaskdel函数_cursor函数OSTaskCreate()

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

OSTaskCreate()函数分析

uc/os系统中,对于任务的描述和管理是通过任务控制快-OS_TCB来实现的,OS_TCB本质上是一些驻留在在RAM中的结构体。由以下内容构成

typedef struct os_tcb {

    OS_STK        *OSTCBStkPtr;//OS_STK定义为32位无符号数据,该行定义当前任务所分配的堆栈的栈顶指针(该栈顶指针是指任务切换后自动保存的r0~r15等一系列数据后的堆栈指针),对于堆栈,uc/os可以对每一个任务分配一个任意大小的堆栈。

 

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

    void          *OSTCBExtPtr;//扩展任务块指针,扩展控制块的引入,使得可以在不改变uc/os源代码的前提下,加入扩展功能,此外如果需要使用该功能,则需在OS_CFG.Huc/os配置文件)中将OS_TASK_CREATE_EXT_EN置一,允许建立任务函数的扩展

    OS_STK        *OSTCBStkBottom;指向任务堆栈的栈底(就是数据最后进入的地址)如果堆栈增长方式是递增的话,那么它指向堆栈的最高地址,反之指向最低地址,改参数在使用OSTaskStkChk()函数是需要使用

    INT32U         OSTCBStkSize;//该参数是任务堆栈大小,对于堆栈大小是指栈中所能容纳的指针数目,而不是字节数目。假设堆栈容量是1000,如果地址宽度是32位的,那么堆栈包含4000字节,但是其容量是1000

    INT16U         OSTCBOpt;//选择项,支持三个选择,OS_TASK_OPT_STK_CHK该参数用于告知TaskCreateExt()函数在建立任务时对堆栈进行检查(uc/os不会自动进行堆栈检查,必须使用改选项来设定),OS_TASK_OPT_STK_CLR该参数设定,则在任务建立的过程中将任务栈清零(只有在需要使用栈检验功能时才将栈清零)OS_TASK_OPT_SAVE_FP该参数是通知任务需要做浮点数运算

    INT16U         OSTCBId;用于存储任务的识别码,现在还没使用,感觉他会发展风linux中的PID

#endif

 

    struct os_tcb *OSTCBNext;

    struct os_tcb *OSTCBPrev;//任务控制块的组成双向链表是所需的变量,分别指向该任务的后一个任务控制快和前一个任务控制块。

 

#if (OS_Q_EN && (OS_MAX_QS >= 2)) || OS_MBOX_EN || OS_SEM_EN

    OS_EVENT      *OSTCBEventPtr;//如果定义了队列,消息邮箱,信号量系统资源,则使用该指针指向事件控制块。

#endif

 

#if (OS_Q_EN && (OS_MAX_QS >= 2)) || OS_MBOX_EN

    void          *OSTCBMsg;//如果定义队列和邮箱,则指针指向所要传递的消息

#endif

 

    INT16U         OSTCBDly;//任务延时的时间,或者等待某事件发生的超时限制,在时钟没每生一次中断的时候,时钟节拍函数OSTimeTick()将通过任务控制块的链表访问该变量并将其减一从而刷新该变量

    INT8U          OSTCBStat;//该变量用于描述任务的状态

    INT8U          OSTCBPrio;//任务优先级

 

      INT8U          OSTCBX;//表示任务优先级在就绪表中的X轴的位置,相当说明该优先级是某一组中的哪一个位元素。

    INT8U          OSTCBY;//表示任务优先级在就绪表中的Y轴的位置,相当说明该优先级是处于第几个组元素

    INT8U          OSTCBBitX;//说明该优先级对应的OSTCBTBL[prio&0x7]中元素的赋值

    INT8U          OSTCBBitY;//说明该优先级对应的OSRdyGrp的元素,将该元素与OSRdyGrp相于就获得当前的OSRdyGrp所对应的值

 

#if OS_TASK_DEL_EN

    BOOLEAN        OSTCBDelReq;该参数表明该任务是否需要删除。只有在OS_FLAG_EN置为一是才会出现在OS_TCB

#endif

} OS_TCB;

Ø  对于OS_TCB的管理,uc/os采用了两个链表进行管理,在任务初始化时所有的空闲OS_TCB被连接成单向的空任务链表。另外当任务建立时,空任务控制块指针OSTCBFreeList指向的控制块分配给该任务,当有多个任务建立时,所申请的任务控制块构成一个双向的任务控制块链表

Ø  对于任务就绪表的说明:在uc/os中最多支持64个任务,并为每一个任务指派一个优先级,对于任务的就绪查询,其使用任务就绪表。每个任务的就绪态标志都放入就绪表中的,就绪表中有两个变量OSRedyGrpOSRdyTbl[]。在OSRdyGrp中,任务按优先级分组,8个任务为一组。OSRdyGrp中的每一位表示8组任务中每一组中是否有进入就绪态的任务。任务进入就绪态时,就绪表OSRdyTbl[]中的相应元素的相应位也置位。就绪表OSRdyTbl[]数组的大小取决于OS_LOWEST_PR1O(见文件OS_CFG.H)。当用户的应用程序中任务数目比较少时,减少OS_LOWEST_PR1O的值可以降低μC/OS-Ⅱ对RAM(数据空间)的需求量。

Ø  任务堆栈的栈顶是指,将CPU全部寄存器压入堆栈后的SP,而不是说堆栈的起始地址。

 

 

 

 

 

 

 

OS_TCBInit()函数分析

函数名称:

OS_TCBInit()

函数功能:

任务控制块初始化

函数入口接口:

任务优先级prio、任务堆栈栈顶ptos、任务堆栈栈底pbos、任务id、任务堆栈大小stk_size、任务扩展指针pext、任务选项opt

函数出口接口:

8位无符号数,表明是否初始化成功

主要调用函数:

函数主要执行逻辑流程:

ostaskdel函数_cursor函数

 

OS_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         //
    OS_CPU_SR cpu_sr;
#endif   
    OS_TCB    *ptcb;//
声明一个指向任务控制块的指针


    OS_ENTER_CRITICAL();//
防止其他任务抢占该TCB故要关中断
    ptcb = OSTCBFreeList;//
从空任务链表中申请一个新的控制块(空任务链表是单向链表,大小由OS_MASK_TASKS决定)                                 

if (ptcb != (OS_TCB *)0) {//如果指针分配成功,即分配的tcb有实际地址
        OSTCBFreeList        =ptcb->OSTCBNext;//
则空任务块指针OSTCBFreeList指向下一个空TCB

OS_EXIT_CRITICAL();//此时该任务已经占有该任务控制块,开中断来初始化TCB中其余变元,减少关中断时间。
        ptcb->OSTCBStkPtr    =ptos; //
初始话任务堆栈栈顶(参数传入)

    ptcb->OSTCBPrio      = (INT8U)prio;//初始化优先级(参数传入)
        ptcb->OSTCBStat      = OS_STAT_RDY;//
任务状态为就绪

    ptcb->OSTCBDly       = 0;//设置任务延时为0,即不延时

#if OS_TASK_CREATE_EXT_EN > 0//如果在OS_FH.H中使能了OS_TASK_CREATE_EXT_EN额外的变元就被插入到TCB
        ptcb->OSTCBExtPtr    = pext
//任务扩展块的指针
        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;//
布尔变量是否出现取决于OS_TASK_EN是否被设置(如果不打算删除任务的话,将节省一个布尔变量的空间)
#endif

        ptcb->OSTCBY         = prio >> 3;//提前计算任务就绪表所需要的一些变量
        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;//
将任务控制块优先级表中对应变量赋值为该TCB地址
        ptcb->OSTCBNext    = OSTCBList;//
将初始化好的TCB加入到以用TCB双向链表中
        ptcb->OSTCBPrev    = (OS_TCB *)0;//TCB
链表的每一次加入,总是加入到链表最前面的一个位置,故新加入的TCB前一个TCB应该为空
        if (OSTCBList != (OS_TCB *)0) {//OSTCBList
是双向链表的头结点,如果头结点是非空的话,证明该链表中非空了,故需将新申请的TCB块于前一个TCB连接起来
            OSTCBList->OSTCBPrev = ptcb;//
将前一个TCB控制块中的OSTCBPrev指向新申请的TCB,此时OSTCBList指向的是旧的TCB
        }
        OSTCBList               = ptcb;//
TCB加入成功后,将双向链表头指针指向新加入的TCB(新的TCB总是加载到双向链表的链表头)
        OSRdyGrp               |= ptcb->OSTCBBitY//
更新任务就绪表的内容(此次修改任务就绪组变量其中OSTCBBitY已经在前面计算过)
        OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;//
更新任务就绪位表
        OS_EXIT_CRITICAL();
        return (OS_NO_ERR);
返回TCB初始化成功
    }
    OS_EXIT_CRITICAL();
    return (OS_NO_MORE_TCB);//
如果该TCB指针为零则返回OS_NO_MORE_TCB
}

Ø  该函数的基本过程:申请TCB->初始化TCB中的变量->更新任务控制块优先级表->TCB加入到以用TCB链表->更新任务就绪表

 

 

 

OS_TaskStkInit()分析

函数名称:

OS_TaskStkInit()

函数功能:

任务堆栈初始化

函数入口接口:

任务入口地址、任务参数、堆栈原始栈顶、选项

函数出口接口:

初始化寄存器后的堆栈地址(堆栈栈顶)

主要调用函数:

逻辑流程

ostaskdel函数_cursor函数

示意性代码:

OS_STK *OSTaskStkInit(void (*task)(void *pd),void *pdata,OS_STK *ptos,INT16U opt)

{

 模拟带参数(pdata)的函数调用

模拟ISR向量

按照预先设计的寄存器值初始化堆栈结构

返回栈顶指针给调用该函数的函数

 

 

 

 

 

 

 

 

OSTaskStkInit()函数源码(针对ARM7LPC2200,该源码根据不同的CPU有不同的形式)

OS_STK *OSTaskStkInit (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT16U opt)

{

    OS_STK *stk;

    opt    = opt;                           /* ‘opt’  没有使用。作用是避免编译器警告    */

stk    = ptos;                          /* 获取堆栈指针                                       */

/* 建立任务环境,使用满递减堆栈       */

    *stk = (OS_STK) task;                   /*  pc  */

    *–stk = (OS_STK) task;                 /*  lr  */

 

    *–stk = 0;                             /*  r12  */

    *–stk = 0;                             /*  r11  */

    *–stk = 0;                             /*  r10  */

    *–stk = 0;                             /*  r9   */

    *–stk = 0;                             /*  r8   */

    *–stk = 0;                             /*  r7   */

    *–stk = 0;                             /*  r6   */

    *–stk = 0;                             /*  r5   */

    *–stk = 0;                             /*  r4   */

    *–stk = 0;                             /*  r3   */

    *–stk = 0;                             /*  r2   */

    *–stk = 0;                             /*  r1   */

    *–stk = (unsigned int) pdata;          /*  r0,第一个参数使用R0传递   */

    *–stk = (USER_USING_MODE|0x00);     /*  spsr,允许 IRQ, FIQ 中断   */

    *–stk = 0;                             /*  关中断计数器OsEnterSum;    */

 

    return (stk);

}

Ø  在任务第一次开始执行时,操作系统首先得到任务的任务控制块,然后从任务控制块得到任务的堆栈指针,再把这个堆栈指针送到R13(SP)。然后再OSCtxSw()函数中把初始化的各个寄存器的值送到对应的CPU寄存器,所以在OSTaskStkInit()函数里不用处理R13。在任务执行过一次之后,任务被中断切换到其它任务之前,就会从R13(SP)得到堆栈指针当前的位置,在OSCtxSw()函数中把CPUR0-R12,R14等值压到R13(SP)指定的堆栈中。所以R13的内容是不需要初始化的。

Ø  OSTaskStkInit()中数据进栈的顺序要和OSCtxSw()中数据出栈的顺序对应。
PC
值是最后出栈,所以要最先进栈。把任务函数的地址压入堆栈。出栈后,任务函数地址送入PC后,就开始执行任务函数。

Ø  R14是返回地址,但是任务函数是一个无限循环,只有在任务调度时才会退出,而在任务调度时切换到另一个任务时,会把另一个任务堆栈中存储的R14的值送到R14,保证程序在另一个任务被中断时的断点继续运行。所以在初始化堆栈时,R14的值是没有用的,可以随意赋值。

Ø  R1-R12可随便赋值,但是赋值的形式最好是反映出堆栈增长方式

Ø  返回的地址是堆栈压入上述寄存器后的指针,而不是对战最初的指针

Ø  CPSR在压入堆栈的时候确保其是允许IRQFIQ

 

 

 

 

OS_Sched()函数分析

函数名称:

OS_Sched()

函数功能:

任务调度(该函数相当于判断是否需要进行任务切换,具体任务切换是由OS_TASK_SW()汇编宏来完成的

函数入口接口:

函数出口接口:

主要调用函数:

OS_TASK_SW()

函数逻辑流程

ostaskdel函数_cursor函数

OSSched()函数源码

void OSSched (void)

{

    INT8U y;

 

 

    OS_ENTER_CRITICAL();

    if ((OSLockNesting | OSIntNesting) == 0) {//判断任务调度器是否上锁、该任务切换请求是否是在ISR中请求的

        y             = OSUnMapTbl[OSRdyGrp];//获得当前最高优先级任务处于就绪表的第几组

        OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]);//OSUNMapTbly】是获得其处于组元素中的第几位,将组元素左移三位相加位元素后强制类型转换得当前优先级最高的任务,这个表是uc/os提前设定好的,其实我也每台看明白他是怎么来的

        if (OSPrioHighRdy != OSPrioCur) {//判断最高优先级任务是否是现在运行的任务

            OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];//根据当前最高优先级从任务控制块优先级表中获得当前最高优先级控制块的入口地址

            OSCtxSwCtr++;//任务切换次数++,该变量是跟踪任务切换次数的                                                        

            OS_TASK_SW();//宏调用,完成实际上的任务切换

        }

    }

    OS_EXIT_CRITICAL();

}

Ø  在任务切换的所有代码都是临界段代码,这样是防止ISR在将高优先级任务置位,干扰此次任务切换。

Ø  判断任务切换请求是否是ISR的请求的原因是OS_TASK_SW()应用在任务级,它只是简单的将处理器寄存器保存到被挂起的任务堆栈中,并且从堆栈中回复要运行的更高优先级任务。

 

 

OS_TASK_SW宏调用分析

函数名称:

OS_TASK_SW(实际上是调用软中断)

函数功能:

完成任务切换

函数入口接口:

函数出口接口:

主要调用函数:

软中断

 

#define OS_TASK_SW() asm INT #080h //此处使用SWI指令进行分析

 

Ø  对于任务的切换uc/os使用软中断来实现

对于软中断将会在专门来说明一下,这点看了好久才JB看明白

 

 

 

 

 

 

OSTaskCreate()分析

前面说了那么多,终于该到OSTaskCreate()勒,在uc/os中,该函数的作用是创建一个任务(其实就是个线程)来完成一定的功能。

函数名称:

OSTaskCreate()

函数功能:

建立一个任务

函数入口接口:

void (*task)(void *pd)任务入口地址指针

void *pdata传给任务参数的指针(一般用不到)

OS_STK *ptos任务堆栈栈顶指针(在初始化任务堆栈的时候使用)

INT8U prio任务优先级,作用你懂得

函数出口接口:

INT8U 是否建立成功标志

主要调用函数:

OSTaskStkInit()任务堆栈初始化

OSTCBInit*()任务控制快初始化,说白了就是从空TCB取个空TCB然后该结构体内容赋值,再将该TCB加载到双向链表上

OSSched()任务调度

函数流程逻辑

ostaskdel函数_cursor函数

 

 

 

OSTaskCreate()源码分析

INT8U OSTaskCreate (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT8U prio)

{

#if OS_CRITICAL_METHOD == 3

    OS_CPU_SR  cpu_sr;

#endif

    OS_STK    *psp;

    INT8U      err;

   

#if OS_ARG_CHK_EN > 0

    if (prio > OS_LOWEST_PRIO) { //确保该优先级高于设定的最低优先级  

        return (OS_PRIO_INVALID);

    }

#endif

    OS_ENTER_CRITICAL();

    if (OSTCBPrioTbl[prio] == (OS_TCB *)0) { //确保该优先级还未分配,如果该优先级已被分配,那么在任务控制块优先级表中存放的是实际分配任务控制块的入口地址,未分配则地址为空

        OSTCBPrioTbl[prio] = (OS_TCB *)1; //只是简单的将该优先级对应数组元素置位一,表示该优先级现在被分配了,其不是赋值具体的TCB入口地址是为了减少关中断的时间,(具体入口地址是在OSTCBINI()函数中从空任务控制池中分配的)

                                             /

        OS_EXIT_CRITICAL();

        psp = (OS_STK *)OSTaskStkInit(task, pdata, ptos, 0);//堆栈初始化,返回的是压入一定寄存器后的SP   

        err = OS_TCBInit(prio, psp, (OS_STK *)0, 0, 0, (void *)0, 0);//初始化TCB

        if (err == OS_NO_ERR) {

            OS_ENTER_CRITICAL();

            OSTaskCtr++; //该变量是用来追踪当前任务数目的

            OS_EXIT_CRITICAL();

            if (OSRunning == TRUE) { //确保uc/os已经开始多任务调度了

                OS_Sched();//找到当前最高优先级任务,开始任务调度

            }

        } else {

            OS_ENTER_CRITICAL();

            OSTCBPrioTbl[prio] = (OS_TCB *)0;//如果TCB申请失败,那么将任务控制块优先级表对应元素清零,放弃此次任务建立

            OS_EXIT_CRITICAL();

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/196824.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 基于speech模块的久坐提醒小程序「建议收藏」

    基于speech模块的久坐提醒小程序「建议收藏」每天在电脑前坐很长的时间,因为有时候太过投入一下子就过去了若干个小时,容易猝死。于是心血来潮的想要写一个防久坐提醒小程序:第一种模式(最简单模式),若输入伏案工作时间数值不对则产生一个错误并退出。代码如下:importspeechimporttimeclassDebug:def__init__(self):self.start_time=time.time()self.minutes=int(input(“How

  • TCP四次挥手过程

    TCP四次挥手过程四次挥手状态转化:A、B连接建立状态ESTABLISHED->A终止等待1状态FIN-WAIT-1->B关闭等待状态2CLOSE-WAIT->A终止等待2状态FIN-WAIT-2->B最后确认状态LAST-ACK->A时间等待状态TIME-WAIT->B、A关闭状态CLOSED 四次挥手过程 第一次挥手:A数据传输完毕需…

  • docker(11)Dockerfile 中的COPY与ADD 命令[通俗易懂]

    docker(11)Dockerfile 中的COPY与ADD 命令[通俗易懂]前言Dockerfile中提供了两个非常相似的命令COPY和ADD,本文尝试解释这两个命令的基本功能,以及其异同点,然后总结其各自适合的应用场景。Build上下文的概念在使用dock

  • Latex角标(subscript/superscript)

    Latex角标(subscript/superscript)

  • hotumoyi吉他_木棒能做什么

    hotumoyi吉他_木棒能做什么乔治拿来一组等长的木棒,将它们随机地砍断,使得每一节木棍的长度都不超过 50 个长度单位。然后他又想把这些木棍恢复到为裁截前的状态,但忘记了初始时有多少木棒以及木棒的初始长度。请你设计一个程序,帮助乔治计算木棒的可能最小长度。每一节木棍的长度都用大于零的整数表示。输入格式输入包含多组数据,每组数据包括两行。第一行是一个不超过 64 的整数,表示砍断之后共有多少节木棍。第二行是截断以后,所得到的各节木棍的长度。在最后一组数据之后,是一个零。输出格式为每组数据,分别输出原始木棒的可能最小长度

  • python_sklearn库的使用

    python_sklearn库的使用sklearn库的使用

    2022年10月17日

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号