μC/OS-II---互斥信号量管理2(os_mutex.c)

目录

  • 背景:优先级反转问题
  • 互斥信号量管理
    • 互斥信号量发出(释放)
    • 互斥信号量获取/无等待
    • 互斥信号量状态查询

μC/OS-II---互斥信号量管理2(os_mutex.c)_第1张图片

背景:优先级反转问题

  • 在高优先级任务等待低优先级任务释放资源时,第三个中等优先级任务抢占了低优先级任务。阻塞时间是无法预测的,可能导致高优先级任务无法满足deadline。这是需要解决的问题。μC/OS-II采用的办法:优先级继承协议。【实际采用的方法是由互斥信号量先预占一个优先级】

互斥信号量管理

互斥信号量发出(释放)

INT8U  OSMutexPost (OS_EVENT *pevent)
{
	INT8U      pcp;                                   /* Priority ceiling priority                     */
	INT8U      prio;
#if OS_CRITICAL_METHOD == 3u                          /* Allocate storage for CPU status register      */
	OS_CPU_SR  cpu_sr = 0u;
#endif
	
	if (OSIntNesting > 0u)                            /* See if called from ISR ...                    */
	{
		return (OS_ERR_POST_ISR);                     /* ... can't POST mutex from an ISR              */
	}
	
#if OS_ARG_CHK_EN > 0u
	
	if (pevent == (OS_EVENT *)0)                      /* Validate 'pevent'                             */
	{
		return (OS_ERR_PEVENT_NULL);
	}
	
#endif
	
	if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX)   /* Validate event block type                     */
	{
		return (OS_ERR_EVENT_TYPE);
	}
	
	OS_ENTER_CRITICAL();
	pcp  = (INT8U) (pevent->OSEventCnt >> 8u);        /* Get priority ceiling priority of mutex        */
	prio = (INT8U) (pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8); /* Get owner's original priority      */
	
	if (OSTCBCur != (OS_TCB *)pevent->OSEventPtr)     /* See if posting task owns the MUTEX            */
	{
		OS_EXIT_CRITICAL();
		return (OS_ERR_NOT_MUTEX_OWNER);
	}
	
	if (pcp != OS_PRIO_MUTEX_CEIL_DIS)
	{
		if (OSTCBCur->OSTCBPrio == pcp)               /* Did we have to raise current task's priority? */
		{
			OSMutex_RdyAtPrio (OSTCBCur, prio);       /* Restore the task's original priority          */
		}
		
		OSTCBPrioTbl[pcp] = OS_TCB_RESERVED;          /* Reserve table entry                           */
	}
	
	if (pevent->OSEventGrp != 0u)                     /* Any task waiting for the mutex?               */
	{
		/* Yes, Make HPT waiting for mutex ready         */
		prio                = OS_EventTaskRdy (pevent, (void *)0, OS_STAT_MUTEX, OS_STAT_PEND_OK);
		pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8;  /*      Save priority of mutex's new owner       */
		pevent->OSEventCnt |= prio;
		pevent->OSEventPtr  = OSTCBPrioTbl[prio];     /*      Link to new mutex owner's OS_TCB         */
		
		if ((pcp  != OS_PRIO_MUTEX_CEIL_DIS) &&
				(prio <= pcp))                            /*      PCP 'must' have a SMALLER prio ...       */
		{
			OS_EXIT_CRITICAL();                       /*      ... than current task!                   */
			OS_Sched();                               /*      Find highest priority task ready to run  */
			return (OS_ERR_PCP_LOWER);
		}
		
		else
		{
			OS_EXIT_CRITICAL();
			OS_Sched();                               /*      Find highest priority task ready to run  */
			return (OS_ERR_NONE);
		}
	}
	
	pevent->OSEventCnt |= OS_MUTEX_AVAILABLE;         /* No,  Mutex is now available                   */
	pevent->OSEventPtr  = (void *)0;
	OS_EXIT_CRITICAL();
	return (OS_ERR_NONE);
}

互斥信号量获取/无等待

#if OS_MUTEX_ACCEPT_EN > 0u
BOOLEAN  OSMutexAccept (OS_EVENT  *pevent,
												INT8U     *perr)
{
	INT8U      pcp;                                    /* Priority Ceiling Priority (PCP)              */
#if OS_CRITICAL_METHOD == 3u                           /* Allocate storage for CPU status register     */
	OS_CPU_SR  cpu_sr = 0u;
#endif
#ifdef OS_SAFETY_CRITICAL
	
	if (perr == (INT8U *)0)
	{
		OS_SAFETY_CRITICAL_EXCEPTION();
		return (OS_FALSE);
	}
	
#endif
#if OS_ARG_CHK_EN > 0u
	
	if (pevent == (OS_EVENT *)0)                       /* Validate 'pevent'                            */
	{
		*perr = OS_ERR_PEVENT_NULL;
		return (OS_FALSE);
	}
	
#endif
	
	if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX)    /* Validate event block type                    */
	{
		*perr = OS_ERR_EVENT_TYPE;
		return (OS_FALSE);
	}
	
	if (OSIntNesting > 0u)                             /* Make sure it's not called from an ISR        */
	{
		*perr = OS_ERR_PEND_ISR;
		return (OS_FALSE);
	}
	
	OS_ENTER_CRITICAL();                               /* Get value (0 or 1) of Mutex                  */
	pcp = (INT8U) (pevent->OSEventCnt >> 8u);          /* Get PCP from mutex                           */
	
	if ((pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_AVAILABLE)
	{
		pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8;   /*      Mask off LSByte (Acquire Mutex)         */
		pevent->OSEventCnt |= OSTCBCur->OSTCBPrio;     /*      Save current task priority in LSByte    */
		pevent->OSEventPtr  = (void *)OSTCBCur;        /*      Link TCB of task owning Mutex           */
		
		if ((pcp != OS_PRIO_MUTEX_CEIL_DIS) &&
				(OSTCBCur->OSTCBPrio <= pcp))              /*      PCP 'must' have a SMALLER prio ...      */
		{
			OS_EXIT_CRITICAL();                       /*      ... than current task!                  */
			*perr = OS_ERR_PCP_LOWER;
		}
		
		else
		{
			OS_EXIT_CRITICAL();
			*perr = OS_ERR_NONE;
		}
		
		return (OS_TRUE);
	}
	
	OS_EXIT_CRITICAL();
	*perr = OS_ERR_NONE;
	return (OS_FALSE);
}
#endif

互斥信号量状态查询

#if OS_MUTEX_QUERY_EN > 0u
INT8U  OSMutexQuery (OS_EVENT       *pevent,
										 OS_MUTEX_DATA  *p_mutex_data)
{
	INT8U       i;
	OS_PRIO    *psrc;
	OS_PRIO    *pdest;
#if OS_CRITICAL_METHOD == 3u                     /* Allocate storage for CPU status register           */
	OS_CPU_SR   cpu_sr = 0u;
#endif
	
	if (OSIntNesting > 0u)                                 /* See if called from ISR ...               */
	{
		return (OS_ERR_QUERY_ISR);                         /* ... can't QUERY mutex from an ISR        */
	}
	
#if OS_ARG_CHK_EN > 0u
	
	if (pevent == (OS_EVENT *)0)                           /* Validate 'pevent'                        */
	{
		return (OS_ERR_PEVENT_NULL);
	}
	
	if (p_mutex_data == (OS_MUTEX_DATA *)0)                /* Validate 'p_mutex_data'                  */
	{
		return (OS_ERR_PDATA_NULL);
	}
	
#endif
	
	if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX)        /* Validate event block type                */
	{
		return (OS_ERR_EVENT_TYPE);
	}
	
	OS_ENTER_CRITICAL();
	p_mutex_data->OSMutexPCP  = (INT8U) (pevent->OSEventCnt >> 8u);
	p_mutex_data->OSOwnerPrio = (INT8U) (pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8);
	
	if (p_mutex_data->OSOwnerPrio == 0xFFu)
	{
		p_mutex_data->OSValue = OS_TRUE;
	}
	
	else
	{
		p_mutex_data->OSValue = OS_FALSE;
	}
	
	p_mutex_data->OSEventGrp  = pevent->OSEventGrp;        /* Copy wait list                           */
	psrc                      = &pevent->OSEventTbl[0];
	pdest                     = &p_mutex_data->OSEventTbl[0];
	
	for (i = 0u; i < OS_EVENT_TBL_SIZE; i++)
	{
		*pdest++ = *psrc++;
	}
	
	OS_EXIT_CRITICAL();
	return (OS_ERR_NONE);
}
#endif

你可能感兴趣的:(μC/OS-II学习,c语言)