OS_FLAG.C(2)

309 阅读4分钟

本篇介绍OS_FLAG.C文件中的创建事件标志组函数*OSFlagCreate (OS_FLAGS  flags,INT8U *perr)和删除事件标志组函数 *OSFlagDel (OS_FLAG_GRP  *pgrp,INT8U  opt,INT8U  *perr)。

OS_FLAG_GRP  *OSFlagCreate (OS_FLAGS  flags,INT8U    *perr)创建事件标志组:

/*$PAGE*/
/*
*********************************************************************************************************
*                                           CREATE AN EVENT FLAG
*												创建事件标志组
* Description: This function is called to create an event flag group.
*描述:该函数是用来创建一个事件标志组。
* Arguments  : flags         Contains the initial value to store in the event flag group.
*参数:						--flags:事件标志组的事件标志初值
*              perr          is a pointer to an error code which will be returned to your application:
*                               OS_ERR_NONE               if the call was successful.
*                               OS_ERR_CREATE_ISR         if you attempted to create an Event Flag from an
*                                                         ISR.
*                               OS_ERR_FLAG_GRP_DEPLETED  if there are no more event flag groups
*							--perr:指向错误码的指针,该指针将会返回到你的应用程序中。
									OS_ERR_NONE:无错误类型,说明调用成功。
									OS_ERR_CREATE_ISR:从中断中创建一个事件标志
									OS_ERR_FLAG_GRP_DEPLETED:如果系统中没有剩余的空闲事件标志组,需要更改OS_CFG.H中的事件标志组数目配置
* Returns    : A pointer to an event flag group or a NULL pointer if no more groups are available.
*返回值:指向事件标志组的指针,如果没有可以返回的可用指针,返回null。
* Called from: Task ONLY
只能被任务调用
*********************************************************************************************************
*/

OS_FLAG_GRP  *OSFlagCreate (OS_FLAGS  flags,
                            INT8U    *perr)
{
    OS_FLAG_GRP *pgrp;						/*指向事件标志组的指针*/
#if OS_CRITICAL_METHOD == 3u               /*中断类型被设置为3*/
    OS_CPU_SR    cpu_sr = 0u;
#endif

#ifdef OS_SAFETY_CRITICAL					/*如果定义了安全中断*/
    if (perr == (INT8U *)0)					/*如果错误码为0*/
	{
        OS_SAFETY_CRITICAL_EXCEPTION();		/*调用安全中断异常函数*/
    }
#endif

#ifdef OS_SAFETY_CRITICAL_IEC61508
    if (OSSafetyCriticalStartFlag == OS_TRUE) 
	{
        OS_SAFETY_CRITICAL_EXCEPTION();
    }
#endif

    if (OSIntNesting > 0u) /* 如果是从中断函数调用 */
	{                        
        *perr = OS_ERR_CREATE_ISR;	 /* 将错误码指针设置为OS_ERR_CREATE_ISR,不能从中断函数调用 */
        return ((OS_FLAG_GRP *)0);	/*返回0*/
    }
    OS_ENTER_CRITICAL();			/*关中断(进入中断)*/
    pgrp = OSFlagFreeList;          /*pgrp指向空闲事件标志列表,来得到一个空闲事件标志组*/ 
    if (pgrp != (OS_FLAG_GRP *)0)	/*有空闲的事件标志组*/
	{           
        OSFlagFreeList       = (OS_FLAG_GRP *)OSFlagFreeList->OSFlagWaitList; /*分配后,调整系统空闲事件标志组链表指针*/
        pgrp->OSFlagType     = OS_EVENT_TYPE_FLAG;  /* 将标志类型设置为事件标志类型*/
        pgrp->OSFlagFlags    = flags;               /* 事件标志初始化*/
        pgrp->OSFlagWaitList = (void *)0;           /*等待任务链接表指针初始化为NULL*/
		#if OS_FLAG_NAME_EN > 0u					/*如果标志有名字的话,将名字初始化为未命名*/
				pgrp->OSFlagName     = (INT8U *)(void *)"?";
		#endif
        OS_EXIT_CRITICAL();							/*退出中断*/
        *perr                = OS_ERR_NONE;			/*将错误类型设置为OS_ERR_NONE*/
    } 
	else							/*没有空闲的事件标志组*/
	{
        OS_EXIT_CRITICAL();			/*退出中断*/
        *perr                = OS_ERR_FLAG_GRP_DEPLETED;/*将错误码设置为OS_ERR_FLAG_GRP_DEPLETED*/
    }
    return (pgrp);                                  /* Return pointer to event flag group              */
}

流程图如下:

\

其中,上面的“进行相应处理”为:

\

这四个步骤对应代码为:

 OSFlagFreeList       = (OS_FLAG_GRP *)OSFlagFreeList->OSFlagWaitList; /*分配后,调整系统空闲事件标志组链表指针*/
        pgrp->OSFlagType     = OS_EVENT_TYPE_FLAG;  /* 将标志类型设置为事件标志类型*/
        pgrp->OSFlagFlags    = flags;               /* 事件标志初始化*/
        pgrp->OSFlagWaitList = (void *)0;           /*等待任务链接表指针初始化为NULL*/

\

删除事件标志组函数:   *OSFlagDel (OS_FLAG_GRP  *pgrp,INT8U  opt,INT8U  *perr)

/*$PAGE*/
/*
*********************************************************************************************************
*                                     DELETE AN EVENT FLAG GROUP
*										删除事件标志组
* Description: This function deletes an event flag group and readies all tasks pending on the event flag
*              group.
*描述:该功能删除事件标志组并且将事件标志组中所有挂起的任务设为就绪
* Arguments  : pgrp          is a pointer to the desired event flag group.
*参数:						--pgrp:指向事件标志组的指针
*              opt           determines delete options as follows:
*                            opt == OS_DEL_NO_PEND   Deletes the event flag group ONLY if no task pending
*                            opt == OS_DEL_ALWAYS    Deletes the event flag group even if tasks are
*                                                    waiting.  In this case, all the tasks pending will be
*                                                    readied.
*							--opt:删除的方式可以有以下几种选择:
								   OS_DEL_NO_PEND:只有当没有任务挂起时才能删除事件标志组
								   OS_DEL_ALWAYS:即使任务处于等待状态,也要删除事件标志组。这种情况下所有挂起的任务将会处于就绪态。
*              perr          is a pointer to an error code that can contain one of the following values:
*                            OS_ERR_NONE               The call was successful and the event flag group was deleted
*                            OS_ERR_DEL_ISR            If you attempted to delete the event flag group from an ISR
*                            OS_ERR_FLAG_INVALID_PGRP  If 'pgrp' is a NULL pointer.
*                            OS_ERR_EVENT_TYPE         If you didn't pass a pointer to an event flag group
*                            OS_ERR_INVALID_OPT        An invalid option was specified
*                            OS_ERR_TASK_WAITING       One or more tasks were waiting on the event flag
*                                                      group.
*							--perr:指向错误码的指针,该指针可以设置为以下值:
									OS_ERR_NONE:调用成功,事件标志组被删除
									OS_ERR_DEL_ISR:尝试从中断中调用删除函数
									OS_ERR_FLAG_INVALID_PGRP:如果pgrp为空指针
									OS_ERR_EVENT_TYPE:pgrp不是指向事件标志组的指针;
									OS_ERR_INVALID_OPT:opt参数不是指定的值;
									OS_ERR_TASK_WAITING:如果opt参数为OS_DEL_NO_PEND,那么此时有任务等待事件标志组
* Returns    : pgrp          upon error
*              (OS_EVENT *)0 if the event flag group was successfully deleted.
*返回值:如果事件标志组被删除,组则返回空指针;
		如果没有删除,则仍然返回指向该事件标志组的指针。
		后一种情况需要检查出错代码,找出事件标志的失败的原因。
* Note(s)    : 1) This function must be used with care.  Tasks that would normally expect the presence of
*                 the event flag group MUST check the return code of OSFlagAccept() and OSFlagPend().
*              2) This call can potentially disable interrupts for a long time.  The interrupt disable
*                 time is directly proportional to the number of tasks waiting on the event flag group.
	注释:1)该功能需要小心使用,期望事件标志组的任务一定要检测OSFlagAccept()和OSFlagPend()两个函数的返回码。
		  2)该函数有可能长时间关闭中断,其时间长短决定于标志组的任务个数。
*********************************************************************************************************
*/

#if OS_FLAG_DEL_EN > 0u
OS_FLAG_GRP  *OSFlagDel (OS_FLAG_GRP  *pgrp,
                         INT8U         opt,
                         INT8U        *perr)
{
    BOOLEAN       tasks_waiting;		/*有等待任务标志*/
    OS_FLAG_NODE *pnode;				/*标志节点*/
    OS_FLAG_GRP  *pgrp_return;			/*返回指针*/
#if OS_CRITICAL_METHOD == 3u          
    OS_CPU_SR     cpu_sr = 0u;
#endif

#ifdef OS_SAFETY_CRITICAL				/*安全中断*/
    if (perr == (INT8U *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
    }
#endif

#if OS_ARG_CHK_EN > 0u					/*检查参数*/
    if (pgrp == (OS_FLAG_GRP *)0)		/*有效化pgrp*/
	{                       
        *perr = OS_ERR_FLAG_INVALID_PGRP;
        return (pgrp);
    }
#endif
    if (OSIntNesting > 0u)		/*看是否从中断中调用的*/
	{                               
        *perr = OS_ERR_DEL_ISR;     
        return (pgrp);
    }
    if (pgrp->OSFlagType != OS_EVENT_TYPE_FLAG) /*有效化事件组类型*/
	{       
        *perr = OS_ERR_EVENT_TYPE;
        return (pgrp);
    }
    OS_ENTER_CRITICAL();		/*进入中断*/
    if (pgrp->OSFlagWaitList != (void *)0) /*看任务正在等待事件标志是否为空*/
	{  
        tasks_waiting = OS_TRUE;          /*有*/
    }
	else
	{
        tasks_waiting = OS_FALSE;	     /*无*/
    }
    switch (opt)			/*选择删除的方式*/
	{
        case OS_DEL_NO_PEND:          /*无任务挂起才删除*/
             if (tasks_waiting == OS_FALSE)			/*没有任务正在等待*/
			 {
				#if OS_FLAG_NAME_EN > 0u
								 pgrp->OSFlagName     = (INT8U *)(void *)"?";/*名称初始化*/
				#endif
                 pgrp->OSFlagType     = OS_EVENT_TYPE_UNUSED;/*标志类型设置为未被使用*/
                 pgrp->OSFlagWaitList = (void *)OSFlagFreeList; /*将该事件标志组加入到事件标志组空闲链表中*/
                 pgrp->OSFlagFlags    = (OS_FLAGS)0;			/*将标志位设为0*/
                 OSFlagFreeList       = pgrp;					/*空闲列表指针指向新的(进行过删除事件标志组函数)链表*/
                 OS_EXIT_CRITICAL();							/*退出中断*/
                 *perr                = OS_ERR_NONE;			/*错误类型设置为无错误类型*/
                 pgrp_return          = (OS_FLAG_GRP *)0;  /*事件标志组已经被删除,因而返回为0*/
             } 
			 else					/*有任务正在等待*/
			 {
                 OS_EXIT_CRITICAL();/*退出中断*/
                 *perr                = OS_ERR_TASK_WAITING;/*将错误类型设置为OS_ERR_TASK_WAITING*/
                 pgrp_return          = pgrp;				/*将pgrp赋给pgrp_return*/
             }
             break;

        case OS_DEL_ALWAYS:        /*如果为无论有没有挂起,都删除*/
             pnode = (OS_FLAG_NODE *)pgrp->OSFlagWaitList; /*指向等待事件组的节点链表*/
             while (pnode != (OS_FLAG_NODE *)0)			   /*遍历该链表*/
			 {          
                 (void)OS_FlagTaskRdy(pnode, (OS_FLAGS)0);	/*将该链表中的节点指向的任务转为就绪状态*/
                 pnode = (OS_FLAG_NODE *)pnode->OSFlagNodeNext;
             }
			#if OS_FLAG_NAME_EN > 0u							/*如果有名字,将名字初始化*/
						 pgrp->OSFlagName     = (INT8U *)(void *)"?";
			#endif
             pgrp->OSFlagType     = OS_EVENT_TYPE_UNUSED;	/*将标志类型设置为未使用类型*/
             pgrp->OSFlagWaitList = (void *)OSFlagFreeList;/* 将该组返回到空闲列表中*/
             pgrp->OSFlagFlags    = (OS_FLAGS)0;
             OSFlagFreeList       = pgrp;
             OS_EXIT_CRITICAL();							/*退出中断*/
             if (tasks_waiting == OS_TRUE) {               /*如果之前是有任务在等待事件标志组*/
                 OS_Sched();                               /*进行调度(执行最高优先级的任务)*/
             }
             *perr = OS_ERR_NONE;							/*将错误类型设置为无错误类型*/
             pgrp_return          = (OS_FLAG_GRP *)0;      /* 事件标志组已经被删除,返回空*/
             break;

        default:											/*其他情况下*/
             OS_EXIT_CRITICAL();							/*退出中断*/
             *perr                = OS_ERR_INVALID_OPT;		/*将错误码设置为OS_ERR_INVALID_OPT*/
             pgrp_return          = pgrp;					/*将pgrp赋值给pgrp_return*/
             break;
    }
    return (pgrp_return);	/*返回pgrp_return*/							
}
#endif

删除函数流程图为:

\

其中,删除操作为(针对OS_DEL_NO_PEND删除类型):

\

如果删除类型是OS_DEL_ALWAYS:则在上述操作步骤之前加一个:将等待事件组的节点链表中的节点指向的任务转为就绪状态。

对应的代码段为:

#if OS_FLAG_NAME_EN > 0u
	pgrp->OSFlagName     = (INT8U *)(void *)"?";/*名称初始化*/
#endif
pgrp->OSFlagType     = OS_EVENT_TYPE_UNUSED;/*标志类型设置为未被使用*/
pgrp->OSFlagWaitList = (void *)OSFlagFreeList; /*将该事件标志组加入到事件标志组空闲链表中*//*下图<1>*/
pgrp->OSFlagFlags    = (OS_FLAGS)0;			/*将标志位设为0*/
OSFlagFreeList       = pgrp;			/*空闲列表指针指向新的(进行过删除事件标志组函数)链表*//*下图2*/

可能直接理解有点困难,我们图解一下:

\

上图即从原始状态经过程序之后的转化状态。<1><2>对应的代码上面注释也写清楚了。

\