【Ucos-III源码分析】——事件标志组

一、事件标志组创建

 

OSFlagCreate((OS_FLAG_GRP  *)&MyEventFlag,
							 (CPU_CHAR     *)"MyEventFlag",
							 (OS_FLAGS      )0,
							 (OS_ERR       *)&err);

创建我们采用这样一个函数,首先明白事件标志组本质就是一个内核对象里面有一个32位得变量Flags,这个变量每一位或者每几位可以表示一个事件得发生,当等待的任务需要的那几个事件(那几个标志位都被置为0或者1)那么就表示等待成功。

那么在创建时干啥了?

void  OSFlagCreate (OS_FLAG_GRP  *p_grp,
                    CPU_CHAR     *p_name,
                    OS_FLAGS      flags,
                    OS_ERR       *p_err)
{
    CPU_SR_ALLOC();



#ifdef OS_SAFETY_CRITICAL
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return;
    }
#endif

#ifdef OS_SAFETY_CRITICAL_IEC61508
    if (OSSafetyCriticalStartFlag == DEF_TRUE) {
       *p_err = OS_ERR_ILLEGAL_CREATE_RUN_TIME;
        return;
    }
#endif

#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
    if (OSIntNestingCtr > (OS_NESTING_CTR)0) {              /* See if called from ISR ...                             */
       *p_err = OS_ERR_CREATE_ISR;                          /* ... can't CREATE from an ISR                           */
        return;
    }
#endif

#if OS_CFG_ARG_CHK_EN > 0u
    if (p_grp == (OS_FLAG_GRP *)0) {                        /* Validate 'p_grp'                                       */
       *p_err = OS_ERR_OBJ_PTR_NULL;
        return;
    }
#endif

    OS_CRITICAL_ENTER();
    p_grp->Type    = OS_OBJ_TYPE_FLAG;                      /* Set to event flag group type                           */
    p_grp->NamePtr = p_name;
    p_grp->Flags   = flags;                                 /* Set to desired initial value                           */
    p_grp->TS      = (CPU_TS)0;
    OS_PendListInit(&p_grp->PendList);

#if OS_CFG_DBG_EN > 0u
    OS_FlagDbgListAdd(p_grp);
#endif
    OSFlagQty++;

    OS_CRITICAL_EXIT();
   *p_err = OS_ERR_NONE;
}

可以看见在事件标志组得创建得时候非常简单,就是参数检查、赋值变量类型(事件标志组类型)、赋值名字,初始值,时间戳,全局得事件标志组变量++。中间还调用了一个OS_PendListInit这个函数猜都知道,是初始化你事件标志组得等待列表用的。无非就是把等待列表置为空,表示这会儿刚创建 肯定没任务在等待

二、事件标志组的等待

1、除了常规的参数检查之外,进来就是看你要不要清除,就相当于用一次满足了就清除,这个变量要看你传参数opt加了没,加了就清除,没加就算了,然后把ts时间戳置零

    if ((opt & OS_OPT_PEND_FLAG_CONSUME) != (OS_OPT)0) {    /* See if we need to consume the flags                    */
        consume = DEF_TRUE;
    } else {
        consume = DEF_FALSE;
    }
if (p_ts != (CPU_TS *)0) {
        *p_ts = (CPU_TS)0;                                  /* Initialize the returned timestamp                      */
    }

2、这里就是进行了一个眼膜操作(只需要低四位),相当于就是你判断是想所有都置为1、任意一位置为1,所有都置为0、任意一位置为0,这四种分出来四个case,原理都差不多,拿一个分析,上面if满足:就相当于是你现在满足了,你想要的位都置为1了,在看你需不需要清0得标志位,需要就清(取反)

if不满足:这里就是你现在想要的位还没值位,此时又要看你是阻塞还是非阻塞

        非阻塞:直接返回0

        阻塞:添加到等待列表里面去,添加到等待列表还要看你有没有超时等待,如果有还需添加到时钟基准列表里面去,同时还会保存一个状态值到挂起等待的pend data里面去

 mode = opt & OS_OPT_PEND_FLAG_MASK;
    CPU_CRITICAL_ENTER();
    switch (mode) {
        case OS_OPT_PEND_FLAG_SET_ALL:                      /* See if all required flags are set                      */
             flags_rdy = (OS_FLAGS)(p_grp->Flags & flags);  /* Extract only the bits we want                          */
             if (flags_rdy == flags) {                      /* Must match ALL the bits that we want                   */
                 if (consume == DEF_TRUE) {                 /* See if we need to consume the flags                    */
                     p_grp->Flags &= ~flags_rdy;            /* Clear ONLY the flags that we wanted                    */
                 }
                 OSTCBCurPtr->FlagsRdy = flags_rdy;         /* Save flags that were ready                             */
                 if (p_ts != (CPU_TS *)0) {
                    *p_ts  = p_grp->TS;
                 }
                 CPU_CRITICAL_EXIT();                       /* Yes, condition met, return to caller                   */
                 *p_err = OS_ERR_NONE;
                 return (flags_rdy);
             } else {                                       /* Block task until events occur or timeout               */
                 if ((opt & OS_OPT_PEND_NON_BLOCKING) != (OS_OPT)0) {
                     CPU_CRITICAL_EXIT();
                     *p_err = OS_ERR_PEND_WOULD_BLOCK;      /* Specified non-blocking so task would block             */
                     return ((OS_FLAGS)0);
                 } else {                                   /* Specified blocking so check is scheduler is locked     */
                     if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) { /* See if called with scheduler locked ...      */
                         CPU_CRITICAL_EXIT();
                         *p_err = OS_ERR_SCHED_LOCKED;                /* ... can't PEND when locked                   */
                         return ((OS_FLAGS)0);
                     }
                 }

                 OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT();     /* Lock the scheduler/re-enable interrupts                */
                 OS_FlagBlock(&pend_data,
                              p_grp,
                              flags,
                              opt,
                              timeout);
                 OS_CRITICAL_EXIT_NO_SCHED();
             }
             break;

3.任务重新调度回来,这里就有几种情况,看你任务是取消等待、删除、超时这些都直接返回0,后续如果成功的拿到了事件标志组,拿到一下使得任务成功拿到的一个状态,在判断要不要consume,最后在返回就行了。

 OSSched();                                              /* Find next HPT ready to run                             */

    CPU_CRITICAL_ENTER();
    switch (OSTCBCurPtr->PendStatus) {
        case OS_STATUS_PEND_OK:                             /* We got the vent flags                                  */
             if (p_ts != (CPU_TS *)0) {
                *p_ts  = OSTCBCurPtr->TS;
             }
             *p_err = OS_ERR_NONE;
             break;

        case OS_STATUS_PEND_ABORT:                          /* Indicate that we aborted                               */
             if (p_ts != (CPU_TS *)0) {
                *p_ts  = OSTCBCurPtr->TS;
             }
             CPU_CRITICAL_EXIT();
             *p_err = OS_ERR_PEND_ABORT;
             return ((OS_FLAGS)0);

        case OS_STATUS_PEND_TIMEOUT:                        /* Indicate that we didn't get semaphore within timeout   */
             if (p_ts != (CPU_TS *)0) {
                *p_ts  = (CPU_TS  )0;
             }
             CPU_CRITICAL_EXIT();
             *p_err = OS_ERR_TIMEOUT;
             return ((OS_FLAGS)0);

        case OS_STATUS_PEND_DEL:                            /* Indicate that object pended on has been deleted        */
             if (p_ts != (CPU_TS *)0) {
                *p_ts  = OSTCBCurPtr->TS;
             }
             CPU_CRITICAL_EXIT();
             *p_err = OS_ERR_OBJ_DEL;
             return ((OS_FLAGS)0);

        default:
             CPU_CRITICAL_EXIT();
             *p_err = OS_ERR_STATUS_INVALID;
             return ((OS_FLAGS)0);
    }

    flags_rdy = OSTCBCurPtr->FlagsRdy;
    if (consume == DEF_TRUE) {                              /* See if we need to consume the flags                    */
        switch (mode) {
            case OS_OPT_PEND_FLAG_SET_ALL:
            case OS_OPT_PEND_FLAG_SET_ANY:                  /* Clear ONLY the flags we got                            */
                 p_grp->Flags &= ~flags_rdy;
                 break;

#if OS_CFG_FLAG_MODE_CLR_EN > 0u
            case OS_OPT_PEND_FLAG_CLR_ALL:
            case OS_OPT_PEND_FLAG_CLR_ANY:                  /* Set   ONLY the flags we got                            */
                 p_grp->Flags |=  flags_rdy;
                 break;
#endif
            default:
                 CPU_CRITICAL_EXIT();
                 *p_err = OS_ERR_OPT_INVALID;
                 return ((OS_FLAGS)0);
        }
    }
    CPU_CRITICAL_EXIT();
    *p_err = OS_ERR_NONE;                                   /* Event(s) must have occurred                            */
    return (flags_rdy);

三、时间标志组得发布

1、参数检查 不合适就返回,再拿一个时间戳ts = OS_TS_GET();  

if (p_grp == (OS_FLAG_GRP *)0) {                        /* Validate 'p_grp'                                       */
       *p_err  = OS_ERR_OBJ_PTR_NULL;
        return ((OS_FLAGS)0);
    }

    switch (opt) {
        case OS_OPT_POST_FLAG_SET:
        case OS_OPT_POST_FLAG_CLR:
        case OS_OPT_POST_FLAG_SET | OS_OPT_POST_NO_SCHED:
        case OS_OPT_POST_FLAG_CLR | OS_OPT_POST_NO_SCHED:
             break;

        default:
             *p_err = OS_ERR_OPT_INVALID;
             return ((OS_FLAGS)0);
    }

2、这里就分为两部分有一部分就是中断中去处理,再就是非中断处理(先看这个)

flags_cur = OS_FlagPost(p_grp,
                            flags,
                            opt,
                            ts,
                            p_err);

 这里进来就是,看你是要置零还是置1,看你传的opt是什么,并且保存一下刚才的ts

CPU_CRITICAL_ENTER();
    switch (opt) {
        case OS_OPT_POST_FLAG_SET:
        case OS_OPT_POST_FLAG_SET | OS_OPT_POST_NO_SCHED:
             p_grp->Flags |=  flags;                            /* Set   the flags specified in the group             */
             break;

        case OS_OPT_POST_FLAG_CLR:
        case OS_OPT_POST_FLAG_CLR | OS_OPT_POST_NO_SCHED:
             p_grp->Flags &= ~flags;                            /* Clear the flags specified in the group             */
             break;

        default:
             CPU_CRITICAL_EXIT();                               /* INVALID option                                     */
             *p_err = OS_ERR_OPT_INVALID;
             return ((OS_FLAGS)0);
    }
    p_grp->TS   = ts;

再就是要去等待列表里看一下,这里面如果有等待列表的任务刚好在等待我们置为得这个数字的话,那么就把任务从等待列表中移除出去 然后让任务就绪。

p_pend_list = &p_grp->PendList;
    if (p_pend_list->NbrEntries == 0u) {                        /* Any task waiting on event flag group?              */
        CPU_CRITICAL_EXIT();                                    /* No                                                 */
        *p_err = OS_ERR_NONE;
        return (p_grp->Flags);
    }

如果有任务在等待事件标志组,遍历所有的任务,利用头节点和任务tcb,里面又要分你是置零还是任意为0,置1还是任意为1,都分别处理,但是他们在处理完之后都会把任务调用OS_FlagTaskRdy这个函数来表示任务已经成功获取到了事件标志组然后处理任务。这里为什么任务有这个opt这个选项就是任务在pend的时候就拿到了这个并且保存在任务得tcb里面。

 p_pend_data = p_pend_list->HeadPtr;
    p_tcb       = p_pend_data->TCBPtr;
    while (p_tcb != (OS_TCB *)0) {                              /* Go through all tasks waiting on event flag(s)      */
        p_pend_data_next = p_pend_data->NextPtr;
        mode             = p_tcb->FlagsOpt & OS_OPT_PEND_FLAG_MASK;
        switch (mode) {
            case OS_OPT_PEND_FLAG_SET_ALL:                      /* See if all req. flags are set for current node     */
                 flags_rdy = (OS_FLAGS)(p_grp->Flags & p_tcb->FlagsPend);
                 if (flags_rdy == p_tcb->FlagsPend) {
                     OS_FlagTaskRdy(p_tcb,                      /* Make task RTR, event(s) Rx'd                       */
                                    flags_rdy,
                                    ts);
                 }
                 break;

            case OS_OPT_PEND_FLAG_SET_ANY:                      /* See if any flag set                                */
                 flags_rdy = (OS_FLAGS)(p_grp->Flags & p_tcb->FlagsPend);
                 if (flags_rdy != (OS_FLAGS)0) {
                     OS_FlagTaskRdy(p_tcb,                      /* Make task RTR, event(s) Rx'd                       */
                                    flags_rdy,
                                    ts);
                 }
                 break;

#if OS_CFG_FLAG_MODE_CLR_EN > 0u
            case OS_OPT_PEND_FLAG_CLR_ALL:                      /* See if all req. flags are set for current node     */
                 flags_rdy = (OS_FLAGS)(~p_grp->Flags & p_tcb->FlagsPend);
                 if (flags_rdy == p_tcb->FlagsPend) {
                     OS_FlagTaskRdy(p_tcb,                      /* Make task RTR, event(s) Rx'd                       */
                                    flags_rdy,
                                    ts);
                 }
                 break;

            case OS_OPT_PEND_FLAG_CLR_ANY:                      /* See if any flag set                                */
                 flags_rdy = (OS_FLAGS)(~p_grp->Flags & p_tcb->FlagsPend);
                 if (flags_rdy != (OS_FLAGS)0) {
                     OS_FlagTaskRdy(p_tcb,                      /* Make task RTR, event(s) Rx'd                       */
                                    flags_rdy,
                                    ts);
                 }
                 break;
#endif
            default:
                 OS_CRITICAL_EXIT();
                 *p_err = OS_ERR_FLAG_PEND_OPT;
                 return ((OS_FLAGS)0);
        }
        p_pend_data = p_pend_data_next;                         /* Point to next task waiting for event flag(s)       */
        if (p_pend_data != (OS_PEND_DATA *)0) {
            p_tcb = p_pend_data->TCBPtr;
        } else {
            p_tcb = (OS_TCB *)0;
        }
    }

这里得OS_FlagTaskRdy,就是修改任务得一些状态,然后根据任务得一些不同的状态,然后把任务从等待列表移除出去就行了。

void   OS_FlagTaskRdy (OS_TCB    *p_tcb,
                       OS_FLAGS   flags_rdy,
                       CPU_TS     ts)
{
    p_tcb->FlagsRdy   = flags_rdy;
    p_tcb->PendStatus = OS_STATUS_PEND_OK;                  /* Clear pend status                                      */
    p_tcb->PendOn     = OS_TASK_PEND_ON_NOTHING;            /* Indicate no longer pending                             */
    p_tcb->TS         = ts;
    switch (p_tcb->TaskState) {
        case OS_TASK_STATE_RDY:
        case OS_TASK_STATE_DLY:
        case OS_TASK_STATE_DLY_SUSPENDED:
        case OS_TASK_STATE_SUSPENDED:
             break;

        case OS_TASK_STATE_PEND:
        case OS_TASK_STATE_PEND_TIMEOUT:
             OS_TaskRdy(p_tcb);
             p_tcb->TaskState = OS_TASK_STATE_RDY;
             break;

        case OS_TASK_STATE_PEND_SUSPENDED:
        case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:
             p_tcb->TaskState = OS_TASK_STATE_SUSPENDED;
             break;

        default:
             break;
    }
    OS_PendListRemove(p_tcb);
}

在外层就是看你是否要调度,并且把事件标志组得变量作为函数得返回值返回。

    if ((opt & OS_OPT_POST_NO_SCHED) == (OS_OPT)0) {
        OSSched();
    }

    CPU_CRITICAL_ENTER();
    flags_cur = p_grp->Flags;
    CPU_CRITICAL_EXIT();
    *p_err    = OS_ERR_NONE;
    return (flags_cur);

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
嵌入式实时操作系统μC/OS-III是一款非常流行且广泛应用的实时操作系统。它被设计用于嵌入式系统中,满足实时性要求高的应用程序的需求。 uCos-III的电子书是对该实时操作系统的详细介绍和使用指南。这本电子书可以帮助读者了解嵌入式系统的基本概念、实时操作系统的工作原理和应用开发方面的技术。它提供了一系列有关uCos-III的知识和实例,使读者能够快速了解和掌握该实时操作系统的使用方法。 这本电子书主要涵盖以下内容: 1. uCos-III的基本概念:介绍了实时操作系统的定义、特点和应用领域,让读者了解操作系统在嵌入式系统中的重要性和作用。 2. uCos-III的架构和特性:介绍了uCos-III的体系结构和主要特性,如任务调度、时钟管理、内存管理、同步与通信等。 3. uCos-III的安装和配置:详细介绍了如何安装和配置uCos-III实时操作系统,包括编译器设置、硬件支持、内核配置等。 4. uCos-III的任务管理:讲解了任务的创建、删除、挂起和恢复等管理操作,同时介绍了任务优先级和实时调度算法。 5. uCos-III的管理服务和通信机制:介绍了信号量、互斥锁、消息队列、事件标志等管理服务和通信机制,帮助读者实现任务间的同步和通信。 6. uCos-III的中断处理和硬件驱动:讲解了中断处理的机制和方法,以及如何编写硬件驱动程序与uCos-III集成。 这本电子书适合嵌入式系统开发人员、学生以及对实时操作系统感兴趣的人阅读。通过学习这本电子书,读者可以准确理解uCos-III实时操作系统的概念和工作原理,并掌握如何使用uCos-III开发和调试嵌入式应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值