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 >0u
pevent->OSEventName =(INT8U *)(void*)"?";#endifOS_EventWaitListInit(pevent);*perr = OS_ERR_NONE;return(pevent);}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
互斥信号量删除
#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 >0u
pevent->OSEventName =(INT8U *)(void*)"?";#endif
pcp =(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 >0u
pevent->OSEventName =(INT8U *)(void*)"?";#endif
pcp =(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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
互斥信号量获取/等待
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 <=63u
ptcb->OSTCBY =(INT8U)( ptcb->OSTCBPrio >>3u);
ptcb->OSTCBX =(INT8U)( ptcb->OSTCBPrio &0x07u);#else
ptcb->OSTCBY =(INT8U)((INT8U)(ptcb->OSTCBPrio >>4u)&0xFFu);
ptcb->OSTCBX =(INT8U)( ptcb->OSTCBPrio &0x0Fu);#endif
ptcb->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();}