浅析μCOS/II v2.85内核OSFlagPend()和OSFlagPost()

原文来自blog.csdn.net/tutb12345/article/details/5889377, 但是貌似下面的链接才是原始出处, 没有去考证.

浅析μCOS/II v2.85内核OSFlagPend()OSFlagPost()函数工作原理
http://gliethttp.cublog.cn
//对于flag--"事件组"的使用,可以用一个简单的例子做说明:
// 比如,我现在用迅雷下载一部10集的连续剧,我打算10集全部下载完成之后,
//才开始正式看,现在3~10集因为种子原因,先早下完了,现在第1集下到了82%,
//2集下到了97%,因为我的计划是10集全部下完才开始看,而第1集和第2
//由于网络,种子等等各种原因,迟迟不能下载完成,进而导致我的计划被悬停,不能进行,
//已下载的8,也因为前2集没能下完,而白白等待---这就等同于flag事件组,
//1~10,每一集都是一个事件,因为我内定,10个事件全部完成之后,才进入下一事件--"观看"
//所以及早完成自己事件的第3~10,将主动把自己通过flag事件组函数OSFlagPost()登记到事件组上,
//他们不关心,其他友邻事件完成否,只专注自己的事件是否完成,自己的事件一旦完成
//就登记到事件组上,最后3~10,都把自己登记上去了,只剩下第1集和第2,
//一旦某天的某个时刻,2集下完了,那么第2集也把自己登记到事件组上,这样整个事件距离完成
//还剩下一个事件,就是第1集是否下载完成,只要第1集下载完成,那么我内定的"观看"计划
//开始启动,过了3分钟,由于网速提高,竟以300k的速度开始下载第1,1分钟之后,
//1集也下载完成了,1集立即调用OSFlagPost事件组函数,将自己登记到事件组上,
//ok,OSFlagPost()检测到所有事件已经完成,OSFlagPost()将是""自动进入下一事件---"观看"
// 还有一点就是关于flag事件组和Sem,Mbox,Queue的区别之处,flag事件组不使用事件控制矩阵来
//管理被阻塞在事件上的task进程,flag事件组使用pgrp的双向链表来挂接起所有task,
//OSFlagPost()中将遍历这个链表,查找符合当前flag事件的task,将该task从双向链表中摘下
//然后放入就绪控制矩阵中,之所以这样,是因为flag事件组不像Sem,Mbox,Queue那样具有二值性,
//Sem,Mbox,Queue,要么有,要么没有,flag事件组,还要进一步判断,有的话,是什么程度的有.
//----------------------------------------------------------------------
//1.OSFlagPend()函数
OS_FLAGS OSFlagPend(OS_FLAG_GRP *pgrp, OS_FLAGS flags, INT8U wait_type, INT16U timeout, INT8U *perr)
{
    OS_FLAG_NODE node;
    OS_FLAGS flags_rdy;
    INT8U result;
    INT8U pend_stat;
    BOOLEAN consume;
#if OS_CRITICAL_METHOD == 3
    OS_CPU_SR cpu_sr = 0;
#endif

#if OS_ARG_CHK_EN > 0
    if(perr ==(INT8U *)0){
        return((OS_FLAGS)0);
    }
    if(pgrp ==(OS_FLAG_GRP *)0){
        *perr = OS_ERR_FLAG_INVALID_PGRP;
        return((OS_FLAGS)0);
    }
#endif
    if(OSIntNesting > 0){
//ISR,不能使用OSFlagPend()
        *perr = OS_ERR_PEND_ISR;
        return((OS_FLAGS)0);
    }
    if(OSLockNesting > 0){
//μCOS/II v2.85内核已经被强制锁住
        *perr = OS_ERR_PEND_LOCKED;
        return((OS_FLAGS)0);
    }
    if(pgrp->OSFlagType != OS_EVENT_TYPE_FLAG){
//确保该event控制块是flag类型
        *perr = OS_ERR_EVENT_TYPE;
        return((OS_FLAGS)0);
    }
    result =(INT8U)(wait_type & OS_FLAG_CONSUME);
    if(result !=(INT8U)0){
//收到指定事件们之后,复位flag事件组,将相应的事件标志清0
        wait_type &=~(INT8U)OS_FLAG_CONSUME;
        consume = OS_TRUE;
    }else{
        consume = OS_FALSE;
    }
    OS_ENTER_CRITICAL();
    switch(wait_type){
        case OS_FLAG_WAIT_SET_ALL:
            //2007-09-09 gliethttp
            //flag事件组中所有事件都置位才唤醒
             flags_rdy =(OS_FLAGS)(pgrp->OSFlagFlags & flags);
             if(flags_rdy == flags){
            //flag事件组中指定的所有事件都已经登记了
                 if(consume == OS_TRUE){
            //清除flag事件组中的相应事件标志位
                     pgrp->OSFlagFlags &=~flags_rdy;
                 }
                 OSTCBCur->OSTCBFlagsRdy = flags_rdy;//返回成功的flag事件组值
                 OS_EXIT_CRITICAL();
                 *perr = OS_ERR_NONE;
                 return(flags_rdy);
             }else{
//flag事件组中指定的所有事件中,可能有1个还没有完成登记工作,所以本task悬停在flag事件控制矩阵中
            //2007-09-09 gliethttp
            //node为该task在栈空间上分配的数据,因为本task任务需要悬停,所以
            //位于该task栈空间上的node,不会被破坏,它和全局变量性质等同
                 OS_FlagBlock(pgrp,&node, flags, wait_type, timeout);
                 OS_EXIT_CRITICAL();
             }
             break;
        case OS_FLAG_WAIT_SET_ANY:
            //2007-09-09 gliethttp
            //flag事件组中指定的事件们,只要有一个事件发生置位就唤醒
             flags_rdy =(OS_FLAGS)(pgrp->OSFlagFlags & flags);
             if(flags_rdy !=(OS_FLAGS)0){
                 if(consume == OS_TRUE){
            //清除flag事件组中的相应事件标志位
                     pgrp->OSFlagFlags &=~flags_rdy;
                 }
                 OSTCBCur->OSTCBFlagsRdy = flags_rdy;//返回成功的flag事件组值
                 OS_EXIT_CRITICAL();
                 *perr = OS_ERR_NONE;
                 return(flags_rdy);
             }else{
//flag事件组中指定的所有事件中,没有1个进行登记,所以悬停本taskflag事件控制矩阵中
            //2007-09-09 gliethttp
            //node为该task在栈空间上分配的数据,因为本task任务需要悬停,所以
            //位于该task栈空间上的node,不会被破坏,它和全局变量性质等同
                 OS_FlagBlock(pgrp,&node, flags, wait_type, timeout);
                 OS_EXIT_CRITICAL();
             }
             break;
#if OS_FLAG_WAIT_CLR_EN > 0
        case OS_FLAG_WAIT_CLR_ALL:
            //2007-09-09 gliethttp
            //flag事件组中所有事件都清0才唤醒
             flags_rdy =(OS_FLAGS)(~pgrp->OSFlagFlags & flags);
             if(flags_rdy == flags){
            //flag事件组中指定的所有事件都已经把事件自己对应的位清0
                 if(consume == OS_TRUE){
            //还原flag事件组中的相应事件标志位
                     pgrp->OSFlagFlags |= flags_rdy;
                 }
                 OSTCBCur->OSTCBFlagsRdy = flags_rdy;//返回成功的flag事件组值
                 OS_EXIT_CRITICAL();
                 *perr = OS_ERR_NONE;
                 return(flags_rdy);
             }else{
//flag事件组中指定的所有事件中,可能有1个还没有完成清0工作,所以本task悬停在flag事件控制矩阵中
            //2007-09-09 gliethttp
            //node为该task在栈空间上分配的数据,因为本task任务需要悬停,所以
            //位于该task栈空间上的node,不会被破坏,它和全局变量性质等同
                 OS_FlagBlock(pgrp,&node, flags, wait_type, timeout);
                 OS_EXIT_CRITICAL();
             }
             break;
        case OS_FLAG_WAIT_CLR_ANY:
            //2007-09-09 gliethttp
            //flag事件组中指定的事件们,只要有一个事件发生清0就唤醒
             flags_rdy =(OS_FLAGS)(~pgrp->OSFlagFlags & flags);
             if(flags_rdy !=(OS_FLAGS)0){
                 if(consume == OS_TRUE){
            //还原flag事件组中的相应事件标志位
                     pgrp->OSFlagFlags |= flags_rdy;
                 }
                 OSTCBCur->OSTCBFlagsRdy = flags_rdy

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值