Ucos源码分析------事件标志组

Ucos源码分析

1.Ucos源码分析------任务控制块与任务调度
2.Ucos源码分析------事件控制块与事件控制
3.Ucos源码分析------信号量
4.Ucos源码分析------邮箱与队列
5.Ucos源码分析------事件标志组
6.Ucos源码分析------内存管理
7.Ucos源码分析------临界区与中断管理
8.Ucos源码分析------OS启动
9.Ucos总结



事件标志组的等待任务表的实现与其它事件不同:
事件标志组的waitlist指针指向等待节点,代替了其它事件类型的任务等待表。
一个事件标志组的多个任务标志组节点,代表等待该事件标志组的的任务。

1.事件标志组

当某任务要与多个事件同步时,使用事件标志组。
同步方式有独立型同步和关联型同步。

独立型同步:等待多个事件时,任何一个事件发生 ,任务都被同步。
关联型同步:等待多个事件时,所有的事件都发生 ,任务才被同步。

任务标志组控制块的基本成员如下

控制块成员
OSFlagType事件类型,默认为OS_EVENT_TYPE_FLAG
*OSFlagWaitList等待事件标志组的任务节点指针
OSFlagFlags指定位数的任务标志组

任务标志组控制节点,是等待列表的实现形式,是任务标志组事件任务 连接的媒介
任务标志组控制节点的基本成员如下

节点成员
OSFlagNodeNext等待列表中下一个节点的指针
OSFlagNodePrev等待列表中上一个节点的指针
OSFlagNodeTCB该节点所指向的任务,即任务控制块
OSFlagNodeFlagGrp该节点所指向的件标志组控制块
OSFlagNodeFlags该节点所指向的任务标志组
OSFlagNodeWaitType事件等待形式

2.任务的等待与就绪

因为事件标志组的等待任务列表与其他事件不一样,所以任务等待和就绪实现也不一样。

任务等待
事件标志组控制块的等待任务列表的指针(pgrp->OSFlagWaitList)指向第一个调用的任务

static  void  OS_FlagBlock (OS_FLAG_GRP *pgrp, OS_FLAG_NODE *pnode, OS_FLAGS flags, INT8U wait_type, INT16U timeout)
{
    //事件标志组节点
    OS_FLAG_NODE  *pnode_next;

    // 当前任务的 等待事件标志组 状态置位
    OSTCBCur->OSTCBStat      |= OS_STAT_FLAG;
    //  当前任务的等待延时
    OSTCBCur->OSTCBDly        = timeout;              /* Store timeout in task's TCB                   */
#if OS_TASK_DEL_EN > 0
    OSTCBCur->OSTCBFlagNode   = pnode;                /* TCB to link to node                           */
#endif
    //设置事件标志组节点的 事件标志组标志 ,
    pnode->OSFlagNodeFlags    = flags;                /* Save the flags that we need to wait for       */
    //设置事件标志组节点的 事件等待类型
    pnode->OSFlagNodeWaitType = wait_type;            /* Save the type of wait we are doing            */
    //设置事件标志组节点的 任务控制块 为当前任务
    pnode->OSFlagNodeTCB      = (void *)OSTCBCur;     /* Link to task's TCB                            */
    pnode->OSFlagNodeNext     = pgrp->OSFlagWaitList; /* Add node at beginning of event flag wait list */
    pnode->OSFlagNodePrev     = (void *)0;
    //设置事件标志组节点的 事件控制块
    pnode->OSFlagNodeFlagGrp  = (void *)pgrp;         /* Link to Event Flag Group                      */
    pnode_next                = (OS_FLAG_NODE *)pgrp->OSFlagWaitList;
    //当前节点是不是加入的第一个节点
    if (pnode_next != (void *)0) {                    /* Is this the first NODE to insert?             */
        //不是形成双向链表
        pnode_next->OSFlagNodePrev = pnode;           /* No, link in doubly linked list                */
    }
    //将节点加入到 事件标志组事件的 任务等待表
    pgrp->OSFlagWaitList = (void *)pnode;
                                                      /* Suspend current task until flag(s) received   */
    //当前任务移出就绪表                                                 
    if ((OSRdyTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0) {
        OSRdyGrp &= ~OSTCBCur->OSTCBBitY;
    }
}

任务就绪

static  BOOLEAN  OS_FlagTaskRdy (OS_FLAG_NODE *pnode, OS_FLAGS flags_rdy)
{
    OS_TCB   *ptcb;
    BOOLEAN   sched;

    //获取当前时间标志组节点的任务
    ptcb                = (OS_TCB *)pnode->OSFlagNodeTCB;  /* Point to TCB of waiting task             */
    //任务超时清除
    ptcb->OSTCBDly      = 0;
    //任务标志组 等待的事件标志置位
    ptcb->OSTCBFlagsRdy = flags_rdy;
    //任务等待事件标志组 状态清除
    ptcb->OSTCBStat    &= ~OS_STAT_FLAG;
    //判断任务是否是就绪态
    if (ptcb->OSTCBStat == OS_STAT_RDY) {                  /* Put task into ready list                 */
        //是就绪态 将任务移到任务就绪表
        OSRdyGrp               |= ptcb->OSTCBBitY;
        OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
        //任务是就绪态 移到任务就绪表 返回允许调度
        sched                   = TRUE;
    } else {
        //任务是就绪态 移到任务就绪表 返回允许调度
        sched                   = FALSE;
    }
    //将任务标志组节点 移除,将等待任务清除
    OS_FlagUnlink(pnode);
    return (sched);
}

事件标志组节点的删除

void  OS_FlagUnlink (OS_FLAG_NODE *pnode)
{
#if OS_TASK_DEL_EN > 0
    OS_TCB       *ptcb;
#endif
    OS_FLAG_GRP  *pgrp; 
    OS_FLAG_NODE *pnode_prev;
    OS_FLAG_NODE *pnode_next;

    //待删除节点的前一个节点
    pnode_prev = (OS_FLAG_NODE *)pnode->OSFlagNodePrev;
    //待删除节点的后一个节点
    pnode_next = (OS_FLAG_NODE *)pnode->OSFlagNodeNext;
    //如果待删除节点是等待表的第一个节点
    if (pnode_prev == (OS_FLAG_NODE *)0) {                      /* Is it first node in wait list?      */
        //获取该节点对应的事件标志组事件控制块
        pgrp                 = (OS_FLAG_GRP *)pnode->OSFlagNodeFlagGrp;
        //事件标志组事件控制块的 等待表指针指向待删除节点的下一个节点
        pgrp->OSFlagWaitList = (void *)pnode_next;              /*      Update list for new 1st node   */
        //如果后一个节点存在
        if (pnode_next != (OS_FLAG_NODE *)0) {
            //后一个节点 成为等待表的第一个节点
            pnode_next->OSFlagNodePrev = (OS_FLAG_NODE *)0;     /*      Link new 1st node PREV to NULL */
        }
    } else { 
        //节点删除                                                   /* No,  A node somewhere in the list   */
        pnode_prev->OSFlagNodeNext = pnode_next;                /*      Link around the node to unlink */
        //如果后一个节点存在
        if (pnode_next != (OS_FLAG_NODE *)0) {                  /*      Was this the LAST node?        */
            //形成双向链表
            pnode_next->OSFlagNodePrev = pnode_prev;            /*      No, Link around current node   */
        }
    }
#if OS_TASK_DEL_EN > 0
    ptcb                = (OS_TCB *)pnode->OSFlagNodeTCB;
    ptcb->OSTCBFlagNode = (OS_FLAG_NODE *)0;
#endif
}

3.任务标志组的获取

OS_FLAGS OSFlagPend (OS_FLAG_GRP *pgrp, OS_FLAGS flags, INT8U wait_type, INT16U timeout, INT8U *err)
参数:
  pgrp:事件标志组控制块
  flags :事件标志组
  wait_type :等待类型
    OS_FLAG_WAIT_SET_ALL:所有位都置1
    OS_FLAG_WAIT_SET_ANY:任一位置1
    OS_FLAG_WAIT_SET_ALL:所有位都置0
     OS_FLAG_WAIT_SET_ANY:任一位置0
  timeout :超时
  err:获取错误信息的指针
函数还要注意使用完事件标志位后,事件标志位是否清除

OS_FLAGS  OSFlagPend (OS_FLAG_GRP *pgrp, OS_FLAGS flags, INT8U wait_type, INT16U timeout, INT8U *err)
{
#if OS_CRITICAL_METHOD == 3                                /* Allocate storage for CPU status register */
    OS_CPU_SR     cpu_sr;
#endif
    OS_FLAG_NODE  node;
    OS_FLAGS      flags_cur;
    OS_FLAGS      flags_rdy;
    BOOLEAN       consume;

    //不能中断调用
    if (OSIntNesting > 0) {                                /* See if called from ISR ...               */
        *err = OS_ERR_PEND_ISR;                            /* ... can't PEND from an ISR               */
        return ((OS_FLAGS)0);
    }
#if OS_ARG_CHK_EN > 0
    if (pgrp == (OS_FLAG_GRP *)0) {                        /* Validate 'pgrp'                          */
        *err = OS_FLAG_INVALID_PGRP;
        return ((OS_FLAGS)0);
    }
    if (pgrp->OSFlagType != OS_EVENT_TYPE_FLAG) {          /* Validate event block type                */
        *err = OS_ERR_EVENT_TYPE;
        return ((OS_FLAGS)0);
    }
#endif
   //收到指定事件后,复位flag事件组,将相应的事件标志清0 
    if (wait_type & OS_FLAG_CONSUME) {                     /* See if we need to consume the flags      */
        wait_type &= ~OS_FLAG_CONSUME;
        consume    = TRUE;
    } else {
        consume    = FALSE;
    }
/*$PAGE*/
    OS_ENTER_CRITICAL();
    switch (wait_type) {
        //事件标志组 所有标志都置1
        case OS_FLAG_WAIT_SET_ALL:                         /* See if all required flags are set        */
            //事件标志组中已经发生的标志 与 任务所需标志“与”运算,取出任务 关心的任务标志组中的标志
             flags_rdy = pgrp->OSFlagFlags & flags;        /* Extract only the bits we want            */
            //事件标志组中的标志状态,满足任务标志需求
            //flags_rdy与任务请求的标志 要相等   
             if (flags_rdy == flags) {                     /* Must match ALL the bits that we want     */
                //判断使用到的标志是否需要清除
                 if (consume == TRUE) {                    /* See if we need to consume the flags      */
                    //清除使用到的标志位 置0
                     pgrp->OSFlagFlags &= ~flags_rdy;      /* Clear ONLY the flags that we wanted      */
                 }
                 //获取现在任务标志组中的标志
                 flags_cur = pgrp->OSFlagFlags;            /* Will return the state of the group       */
                 OS_EXIT_CRITICAL();                       /* Yes, condition met, return to caller     */
                 *err      = OS_NO_ERR;
                 //返回
                 return (flags_cur);
             }
            //事件标志组中的标志状态,不满足任务需要的标志需求
              else {                                      /* Block task until events occur or timeout */
                //当前任务移出就绪表,当前任务借助事件标志组节点完成等待事件表
                 OS_FlagBlock(pgrp, &node, flags, wait_type, timeout);
                 OS_EXIT_CRITICAL();
             }
             break;
        //事件标志组 任一标志置1
        case OS_FLAG_WAIT_SET_ANY:
            //事件标志组中已经发生的标志 与 任务所需标志“与”运算,取出任务 关心的任务标志组中的标志
             flags_rdy = pgrp->OSFlagFlags & flags;        /* Extract only the bits we want            */
            //事件标志组中的标志状态,满足任务标志需求
            // 满足只发生一个  flags_rdy不为0就可
             if (flags_rdy != (OS_FLAGS)0) {               /* See if any flag set                      */
                //判断使用到的标志是否需要清除
                 if (consume == TRUE) {                    /* See if we need to consume the flags      */
                    //清除使用到的标志位 置0
                     pgrp->OSFlagFlags &= ~flags_rdy;      /* Clear ONLY the flags that we got         */
                 }
                 //获取现在任务标志组中的标志
                 flags_cur = pgrp->OSFlagFlags;            /* Will return the state of the group       */
                 OS_EXIT_CRITICAL();                       /* Yes, condition met, return to caller     */
                 *err      = OS_NO_ERR;
                 //返回
                 return (flags_cur);
             }
              //事件标志组中的标志状态,不满足任务需要的标志需求
              else {                                      /* Block task until events occur or timeout */
                //当前任务移出就绪表,当前任务借助事件标志组节点完成等待事件表
                 OS_FlagBlock(pgrp, &node, flags, wait_type, timeout);
                 OS_EXIT_CRITICAL();
             }
             break;

#if OS_FLAG_WAIT_CLR_EN > 0
        //事件标志组 所有标志都置0
        case OS_FLAG_WAIT_CLR_ALL:                         /* See if all required flags are cleared    */
            // flags_rdy = (~pgrp->OSFlagFlags) & flags; 
            //  取出关心的位,将0 翻转位1 进行判断
             flags_rdy = ~pgrp->OSFlagFlags & flags;       /* Extract only the bits we want            */
            //事件标志组中的标志状态,满足任务标志需求
            //flags_rdy与任务请求的标志 要相等   
             if (flags_rdy == flags) {                     /* Must match ALL the bits that we want     */
                //判断使用到的标志是否需要清除
                 if (consume == TRUE) {                    /* See if we need to consume the flags      */
                     //清除使用到的标志位 置1
                     pgrp->OSFlagFlags |= flags_rdy;       /* Set ONLY the flags that we wanted        */
                 }
                 //获取现在任务标志组中的标志                 
                 flags_cur = pgrp->OSFlagFlags;            /* Will return the state of the group       */
                 OS_EXIT_CRITICAL();                       /* Yes, condition met, return to caller     */
                 *err      = OS_NO_ERR;
                 return (flags_cur);
             }
              //事件标志组中的标志状态,不满足任务需要的标志需求
              else {                                      /* Block task until events occur or timeout */
                //当前任务移出就绪表,当前任务借助事件标志组节点完成等待事件表
                 OS_FlagBlock(pgrp, &node, flags, wait_type, timeout);
                 OS_EXIT_CRITICAL();
             }
             break;
        //事件标志组 任一标志置0
        case OS_FLAG_WAIT_CLR_ANY:
            //  取出关心的位,将0 翻转位1 进行判断
             flags_rdy = ~pgrp->OSFlagFlags & flags;       /* Extract only the bits we want            */
            //事件标志组中的标志状态,满足任务标志需求
            //flags_rdy不为0   
             if (flags_rdy != (OS_FLAGS)0) {               /* See if any flag cleared                  */
                //判断使用到的标志是否需要清除
                 if (consume == TRUE) {                    /* See if we need to consume the flags      */
                     //清除使用到的标志位 置1
                     pgrp->OSFlagFlags |= flags_rdy;       /* Set ONLY the flags that we got           */
                 }
                 //获取现在任务标志组中的标志                 
                 flags_cur = pgrp->OSFlagFlags;            /* Will return the state of the group       */
                 OS_EXIT_CRITICAL();                       /* Yes, condition met, return to caller     */
                 *err      = OS_NO_ERR;
                 return (flags_cur);
             } 
            //事件标志组中的标志状态,不满足任务需要的标志需求
             else {                                      /* Block task until events occur or timeout */
                 //当前任务移出就绪表,当前任务借助事件标志组节点完成等待事件表
                 OS_FlagBlock(pgrp, &node, flags, wait_type, timeout);
                 OS_EXIT_CRITICAL();
             }
             break;
#endif

        default:
             OS_EXIT_CRITICAL();
             flags_cur = (OS_FLAGS)0;
             *err      = OS_FLAG_ERR_WAIT_TYPE;
             return (flags_cur);
    }
    //任务调度
    OS_Sched();                                            /* Find next HPT ready to run               */
    OS_ENTER_CRITICAL();
    //任务超时判断
    if (OSTCBCur->OSTCBStat & OS_STAT_FLAG) {              /* Have we timed-out?                       */
        OS_FlagUnlink(&node);
        OSTCBCur->OSTCBStat = OS_STAT_RDY;                 /* Yes, make task ready-to-run              */
        OS_EXIT_CRITICAL();
        flags_cur           = (OS_FLAGS)0;
        *err                = OS_TIMEOUT;                  /* Indicate that we timed-out waiting       */
    } else {
        //清除使用到的标志位
        if (consume == TRUE) {                             /* See if we need to consume the flags      */
            switch (wait_type) {
                case OS_FLAG_WAIT_SET_ALL:
                case OS_FLAG_WAIT_SET_ANY:                 /* Clear ONLY the flags we got              */
                     pgrp->OSFlagFlags &= ~OSTCBCur->OSTCBFlagsRdy;
                     break;

#if OS_FLAG_WAIT_CLR_EN > 0
                case OS_FLAG_WAIT_CLR_ALL:
                case OS_FLAG_WAIT_CLR_ANY:                 /* Set   ONLY the flags we got              */
                     pgrp->OSFlagFlags |= OSTCBCur->OSTCBFlagsRdy;
                     break;
#endif
            }
        }
        //获取现在任务标志组中的标志  
        flags_cur = pgrp->OSFlagFlags;
        OS_EXIT_CRITICAL();
        *err      = OS_NO_ERR;                             /* Event(s) must have occurred              */
    }
    //返回
    return (flags_cur);
}

4.任务标志组的释放----遍历所有等待任务

OSFlagPost是遍历所有的等待任务,将满足事件标志组的,所有任务从等待列表移除,加入到就绪表。

OS_FLAGS OSFlagPost (OS_FLAG_GRP *pgrp, OS_FLAGS flags, INT8U opt, INT8U *err)
参数:
  pgrp:事件标志组控制块
  flags :事件标志组
  opt:
     OS_FLAG_CLR: 事件标志组中指定的位(flags) 置0
    OS_FLAG_SET :事件标志组中指定的位(flags) 置1
  err:获取错误信息的指针

OS_FLAGS  OSFlagPost (OS_FLAG_GRP *pgrp, OS_FLAGS flags, INT8U opt, INT8U *err)
{
#if OS_CRITICAL_METHOD == 3                          /* Allocate storage for CPU status register       */
    OS_CPU_SR     cpu_sr;
#endif
    OS_FLAG_NODE *pnode;
    BOOLEAN       sched;
    OS_FLAGS      flags_cur;
    OS_FLAGS      flags_rdy;

#if OS_ARG_CHK_EN > 0
    if (pgrp == (OS_FLAG_GRP *)0) {                  /* Validate 'pgrp'                                */
        *err = OS_FLAG_INVALID_PGRP;
        return ((OS_FLAGS)0);
    }
    if (pgrp->OSFlagType != OS_EVENT_TYPE_FLAG) {    /* Make sure we are pointing to an event flag grp */
        *err = OS_ERR_EVENT_TYPE;
        return ((OS_FLAGS)0);
    }
#endif
/*$PAGE*/
    OS_ENTER_CRITICAL();
    switch (opt) {
        //将事件标志组(pgrp->OSFlagFlags)中指定的位(flags) 置0
        case OS_FLAG_CLR:
             pgrp->OSFlagFlags &= ~flags;            /* Clear the flags specified in the group         */
             break;
        //将事件标志组(pgrp->OSFlagFlags)中指定的位(flags) 置1
        case OS_FLAG_SET:
             pgrp->OSFlagFlags |=  flags;            /* Set   the flags specified in the group         */
             break;
        //没有相应操作,报错返回
        default:
             OS_EXIT_CRITICAL();                     /* INVALID option                                 */
             *err = OS_FLAG_INVALID_OPT;
             return ((OS_FLAGS)0);
    }
    sched = FALSE;                                   /* Indicate that we don't need rescheduling       */
    //获取等待任务节点的表头指针
    pnode = (OS_FLAG_NODE *)pgrp->OSFlagWaitList;
    //遍历所有等待任务
    while (pnode != (OS_FLAG_NODE *)0) {             /* Go through all tasks waiting on event flag(s)  */
        //该node管理的任务的等待类型
        switch (pnode->OSFlagNodeWaitType) {
            //事件标志组中所有事件都置1才唤醒
            case OS_FLAG_WAIT_SET_ALL:               /* See if all req. flags are set for current node */
                //获取该任务标志组关心的位
                 flags_rdy = pgrp->OSFlagFlags & pnode->OSFlagNodeFlags;
                 if (flags_rdy == pnode->OSFlagNodeFlags) {
                     if (OS_FlagTaskRdy(pnode, flags_rdy) == TRUE) { /* Make task RTR, event(s) Rx'd   */
                         sched = TRUE;                               /* When done we will reschedule   */
                     }
                 }
                 break;
            //事件标志组中所有事件 任一置1都唤醒
            case OS_FLAG_WAIT_SET_ANY:               /* See if any flag set                            */
                //获取该任务标志组关心的位
                 flags_rdy = pgrp->OSFlagFlags & pnode->OSFlagNodeFlags;
                 if (flags_rdy != (OS_FLAGS)0) {
                     if (OS_FlagTaskRdy(pnode, flags_rdy) == TRUE) { /* Make task RTR, event(s) Rx'd   */
                         sched = TRUE;                               /* When done we will reschedule   */
                     }
                 }
                 break;

#if OS_FLAG_WAIT_CLR_EN > 0
            //事件标志组中所有事件 所有置0才唤醒
            case OS_FLAG_WAIT_CLR_ALL:               /* See if all req. flags are set for current node */
                //获取该任务标志组关心的位
                 flags_rdy = ~pgrp->OSFlagFlags & pnode->OSFlagNodeFlags;
                 if (flags_rdy == pnode->OSFlagNodeFlags) {
                     if (OS_FlagTaskRdy(pnode, flags_rdy) == TRUE) { /* Make task RTR, event(s) Rx'd   */
                         sched = TRUE;                               /* When done we will reschedule   */
                     }
                 }
                 break;
            //事件标志组中所有事件 任一置0都唤醒
            case OS_FLAG_WAIT_CLR_ANY:               /* See if any flag set                            */
                //获取该任务标志组关心的位
                 flags_rdy = ~pgrp->OSFlagFlags & pnode->OSFlagNodeFlags;
                 if (flags_rdy != (OS_FLAGS)0) {
                     if (OS_FlagTaskRdy(pnode, flags_rdy) == TRUE) { /* Make task RTR, event(s) Rx'd   */
                         sched = TRUE;                               /* When done we will reschedule   */
                     }
                 }
                 break;
#endif
        }
        //下一个在等待节点上的任务
        pnode = (OS_FLAG_NODE *)pnode->OSFlagNodeNext; /* Point to next task waiting for event flag(s) */
    }
    OS_EXIT_CRITICAL();
    //系统调度
    if (sched == TRUE) {
        OS_Sched();
    }
    OS_ENTER_CRITICAL();
    //返回当前的事件标志组,如果因为OS_Sched()调度去执行了其它任务
    //这里的OSFlagFlags可能已经被其他任务consume属性复了位
    flags_cur = pgrp->OSFlagFlags;
    OS_EXIT_CRITICAL();
    *err      = OS_NO_ERR;
    return (flags_cur);
}

5.任务,事件标志组控制块,与事件标志组节点关系

一个事件标志组节点 将一个任务和事件标注组控制块绑定
一个事件标志控制块 可以有多个事件标志组节点

在这里插入图片描述

  • 6
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值