OS_EVENT *OSMutexCreate(INT8U prio,INT8U *perr){OS_EVENT *pevent;#ifOS_CRITICAL_METHOD ==3u/* Allocate storage for CPU status register */OS_CPU_SR cpu_sr =0u;#endif#ifdefOS_SAFETY_CRITICALif(perr ==(INT8U *)0){OS_SAFETY_CRITICAL_EXCEPTION();return((OS_EVENT *)0);}#endif#ifdefOS_SAFETY_CRITICAL_IEC61508if(OSSafetyCriticalStartFlag == OS_TRUE){OS_SAFETY_CRITICAL_EXCEPTION();return((OS_EVENT *)0);}#endif#ifOS_ARG_CHK_EN >0uif(prio != OS_PRIO_MUTEX_CEIL_DIS){if(prio >= OS_LOWEST_PRIO)/* Validate PCP */{*perr = OS_ERR_PRIO_INVALID;return((OS_EVENT *)0);}}#endifif(OSIntNesting >0u)/* See if called from ISR ... */{*perr = OS_ERR_CREATE_ISR;/* ... can't CREATE mutex from an ISR */return((OS_EVENT *)0);}OS_ENTER_CRITICAL();if(prio != OS_PRIO_MUTEX_CEIL_DIS){if(OSTCBPrioTbl[prio]!=(OS_TCB *)0)/* Mutex priority must not already exist */{OS_EXIT_CRITICAL();/* Task already exist at priority ... */*perr = OS_ERR_PRIO_EXIST;/* ... ceiling priority */return((OS_EVENT *)0);}OSTCBPrioTbl[prio]= OS_TCB_RESERVED;/* Reserve the table entry */}pevent = OSEventFreeList;/* Get next free event control block */if(pevent ==(OS_EVENT *)0)/* See if an ECB was available */{if(prio != OS_PRIO_MUTEX_CEIL_DIS){OSTCBPrioTbl[prio]=(OS_TCB *)0;/* No, Release the table entry */}OS_EXIT_CRITICAL();*perr = OS_ERR_PEVENT_NULL;/* No more event control blocks */return(pevent);}OSEventFreeList =(OS_EVENT *)OSEventFreeList->OSEventPtr;/* Adjust the free list */OS_EXIT_CRITICAL();pevent->OSEventType = OS_EVENT_TYPE_MUTEX;pevent->OSEventCnt =(INT16U)((INT16U)prio <<8u)| OS_MUTEX_AVAILABLE;/* Resource is avail. */pevent->OSEventPtr =(void*)0;/* No task owning the mutex */#ifOS_EVENT_NAME_EN >0upevent->OSEventName =(INT8U *)(void*)"?";#endifOS_EventWaitListInit(pevent);*perr = OS_ERR_NONE;return(pevent);}
互斥信号量删除
#ifOS_MUTEX_DEL_EN >0u
OS_EVENT *OSMutexDel(OS_EVENT *pevent,INT8U opt,INT8U *perr){BOOLEAN tasks_waiting;OS_EVENT *pevent_return;INT8U pcp;/* Priority ceiling priority */INT8U prio;OS_TCB *ptcb;#ifOS_CRITICAL_METHOD ==3u/* Allocate storage for CPU status register */OS_CPU_SR cpu_sr =0u;#endif#ifdefOS_SAFETY_CRITICALif(perr ==(INT8U *)0){OS_SAFETY_CRITICAL_EXCEPTION();return((OS_EVENT *)0);}#endif#ifOS_ARG_CHK_EN >0uif(pevent ==(OS_EVENT *)0)/* Validate 'pevent' */{*perr = OS_ERR_PEVENT_NULL;return(pevent);}#endifif(pevent->OSEventType != OS_EVENT_TYPE_MUTEX)/* Validate event block type */{*perr = OS_ERR_EVENT_TYPE;return(pevent);}if(OSIntNesting >0u)/* See if called from ISR ... */{*perr = OS_ERR_DEL_ISR;/* ... can't DELETE from an ISR */return(pevent);}OS_ENTER_CRITICAL();if(pevent->OSEventGrp !=0u)/* See if any tasks waiting on mutex */{tasks_waiting = OS_TRUE;/* Yes */}else{tasks_waiting = OS_FALSE;/* No */}switch(opt){case OS_DEL_NO_PEND:/* DELETE MUTEX ONLY IF NO TASK WAITING --- */if(tasks_waiting == OS_FALSE){#ifOS_EVENT_NAME_EN >0upevent->OSEventName =(INT8U *)(void*)"?";#endifpcp =(INT8U)(pevent->OSEventCnt >>8u);if(pcp != OS_PRIO_MUTEX_CEIL_DIS){OSTCBPrioTbl[pcp]=(OS_TCB *)0;/* Free up the PCP */}pevent->OSEventType = OS_EVENT_TYPE_UNUSED;pevent->OSEventPtr = OSEventFreeList;/* Return Event Control Block to free list */pevent->OSEventCnt =0u;OSEventFreeList = pevent;OS_EXIT_CRITICAL();*perr = OS_ERR_NONE;pevent_return =(OS_EVENT *)0;/* Mutex has been deleted */}else{OS_EXIT_CRITICAL();*perr = OS_ERR_TASK_WAITING;pevent_return = pevent;}break;case OS_DEL_ALWAYS:/* ALWAYS DELETE THE MUTEX ---------------- */pcp =(INT8U)(pevent->OSEventCnt >>8u);/* Get PCP of mutex */if(pcp != OS_PRIO_MUTEX_CEIL_DIS){prio =(INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8);/* Get owner's orig prio */ptcb =(OS_TCB *)pevent->OSEventPtr;if(ptcb !=(OS_TCB *)0)/* See if any task owns the mutex */{if(ptcb->OSTCBPrio == pcp)/* See if original prio was changed */{OSMutex_RdyAtPrio(ptcb, prio);/* Yes, Restore the task's original prio */}}}while(pevent->OSEventGrp !=0u)/* Ready ALL tasks waiting for mutex */{(void)OS_EventTaskRdy(pevent,(void*)0, OS_STAT_MUTEX, OS_STAT_PEND_ABORT);}#ifOS_EVENT_NAME_EN >0upevent->OSEventName =(INT8U *)(void*)"?";#endifpcp =(INT8U)(pevent->OSEventCnt >>8u);if(pcp != OS_PRIO_MUTEX_CEIL_DIS){OSTCBPrioTbl[pcp]=(OS_TCB *)0;/* Free up the PCP */}pevent->OSEventType = OS_EVENT_TYPE_UNUSED;pevent->OSEventPtr = OSEventFreeList;/* Return Event Control Block to free list */pevent->OSEventCnt =0u;OSEventFreeList = pevent;/* Get next free event control block */OS_EXIT_CRITICAL();if(tasks_waiting == OS_TRUE)/* Reschedule only if task(s) were waiting */{OS_Sched();/* Find highest priority task ready to run */}*perr = OS_ERR_NONE;pevent_return =(OS_EVENT *)0;/* Mutex has been deleted */break;default:OS_EXIT_CRITICAL();*perr = OS_ERR_INVALID_OPT;pevent_return = pevent;break;}return(pevent_return);}#endif
互斥信号量获取/等待
voidOSMutexPend(OS_EVENT *pevent,INT32U timeout,INT8U *perr){INT8U pcp;/* Priority Ceiling Priority (PCP) */INT8U mprio;/* Mutex owner priority */BOOLEAN rdy;/* Flag indicating task was ready */OS_TCB *ptcb;OS_EVENT *pevent2;INT8U y;#ifOS_CRITICAL_METHOD ==3u/* Allocate storage for CPU status register */OS_CPU_SR cpu_sr =0u;#endif#ifdefOS_SAFETY_CRITICALif(perr ==(INT8U *)0){OS_SAFETY_CRITICAL_EXCEPTION();return;}#endif#ifOS_ARG_CHK_EN >0uif(pevent ==(OS_EVENT *)0)/* Validate 'pevent' */{*perr = OS_ERR_PEVENT_NULL;return;}#endifif(pevent->OSEventType != OS_EVENT_TYPE_MUTEX)/* Validate event block type */{*perr = OS_ERR_EVENT_TYPE;return;}if(OSIntNesting >0u)/* See if called from ISR ... */{*perr = OS_ERR_PEND_ISR;/* ... can't PEND from an ISR */return;}if(OSLockNesting >0u)/* See if called with scheduler locked ... */{*perr = OS_ERR_PEND_LOCKED;/* ... can't PEND when locked */return;}/*$PAGE*/OS_ENTER_CRITICAL();pcp =(INT8U)(pevent->OSEventCnt >>8u);/* Get PCP from mutex *//* Is Mutex available? */if((INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8)== OS_MUTEX_AVAILABLE){pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8;/* Yes, Acquire the resource */pevent->OSEventCnt |= OSTCBCur->OSTCBPrio;/* Save priority of owning task */pevent->OSEventPtr =(void*)OSTCBCur;/* Point to owning task's OS_TCB */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;}if(pcp != OS_PRIO_MUTEX_CEIL_DIS){mprio =(INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8);/* Get priority of mutex owner */ptcb =(OS_TCB *)(pevent->OSEventPtr);/* Point to TCB of mutex owner */if(ptcb->OSTCBPrio > pcp)/* Need to promote prio of owner?*/{if(mprio > OSTCBCur->OSTCBPrio){y = ptcb->OSTCBY;if((OSRdyTbl[y]& ptcb->OSTCBBitX)!=0u)/* See if mutex owner is ready */{OSRdyTbl[y]&=(OS_PRIO)~ptcb->OSTCBBitX;/* Yes, Remove owner from Rdy ...*/if(OSRdyTbl[y]==0u)/* ... list at current prio */{OSRdyGrp &=(OS_PRIO)~ptcb->OSTCBBitY;}rdy = OS_TRUE;}else{pevent2 = ptcb->OSTCBEventPtr;if(pevent2 !=(OS_EVENT *)0)/* Remove from event wait list */{y = ptcb->OSTCBY;pevent2->OSEventTbl[y]&=(OS_PRIO)~ptcb->OSTCBBitX;if(pevent2->OSEventTbl[y]==0u){pevent2->OSEventGrp &=(OS_PRIO)~ptcb->OSTCBBitY;}}rdy = OS_FALSE;/* No */}ptcb->OSTCBPrio = pcp;/* Change owner task prio to PCP */#ifOS_LOWEST_PRIO <=63uptcb->OSTCBY =(INT8U)( ptcb->OSTCBPrio >>3u);ptcb->OSTCBX =(INT8U)( ptcb->OSTCBPrio &0x07u);#elseptcb->OSTCBY =(INT8U)((INT8U)(ptcb->OSTCBPrio >>4u)&0xFFu);ptcb->OSTCBX =(INT8U)( ptcb->OSTCBPrio &0x0Fu);#endifptcb->OSTCBBitY =(OS_PRIO)(1uL<< ptcb->OSTCBY);ptcb->OSTCBBitX =(OS_PRIO)(1uL<< ptcb->OSTCBX);if(rdy == OS_TRUE)/* If task was ready at owner's priority ...*/{OSRdyGrp |= ptcb->OSTCBBitY;/* ... make it ready at new priority. */OSRdyTbl[ptcb->OSTCBY]|= ptcb->OSTCBBitX;}else{pevent2 = ptcb->OSTCBEventPtr;if(pevent2 !=(OS_EVENT *)0)/* Add to event wait list */{pevent2->OSEventGrp |= ptcb->OSTCBBitY;pevent2->OSEventTbl[ptcb->OSTCBY]|= ptcb->OSTCBBitX;}}OSTCBPrioTbl[pcp]= ptcb;}}}OSTCBCur->OSTCBStat |= OS_STAT_MUTEX;/* Mutex not available, pend current task */OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK;OSTCBCur->OSTCBDly = timeout;/* Store timeout in current task's TCB */OS_EventTaskWait(pevent);/* Suspend task until event or timeout occurs */OS_EXIT_CRITICAL();OS_Sched();/* Find next highest priority task ready */OS_ENTER_CRITICAL();switch(OSTCBCur->OSTCBStatPend)/* See if we timed-out or aborted */{case OS_STAT_PEND_OK:*perr = OS_ERR_NONE;break;case OS_STAT_PEND_ABORT:*perr = OS_ERR_PEND_ABORT;/* Indicate that we aborted getting mutex */break;case OS_STAT_PEND_TO:default:OS_EventTaskRemove(OSTCBCur, pevent);*perr = OS_ERR_TIMEOUT;/* Indicate that we didn't get mutex within TO */break;}OSTCBCur->OSTCBStat = OS_STAT_RDY;/* Set task status to ready */OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK;/* Clear pend status */OSTCBCur->OSTCBEventPtr =(OS_EVENT *)0;/* Clear event pointers */#if(OS_EVENT_MULTI_EN >0u)OSTCBCur->OSTCBEventMultiPtr =(OS_EVENT **)0;#endifOS_EXIT_CRITICAL();}