...
Let’s use an example to illustrate how µC/OS-II mutexes work. Listing 8.1 shows three tasks that may need to access a common resource. To access the resource, each task must pend on the mutex ResourceMutex. Task #1 has the highest priority (10), task #2 has a medium priority (15) and task #3, the lowest (20). An unused priority just above the highest task priority (i.e., priority 9) will be reserved as the Priority Ceiling Priority (PCP).Suppose that this application has been running for a while and that, at some point, task #3 accesses the common resource first and thus acquires the mutex. Task #3 runs for a while and then gets preempted by task #1. Task #1 needs the resource and thus attempts to acquire the mutex (by calling OSMutexPend()
). In this case, OSMutexPend()
notices that a higher priority task needs the resource and thus raises the priority of task #3 to 9 which forces a context switch back to task #3. Task #3 will proceed and hopefully release the resource quickly. When done with the resource, task #3 will call OSMutexPost()
to release the mutex. OSMutexPost()
will notice that the mutex was owned by a lower priority task that got its priority raised and thus, will return task #3 to it’s original priority. OSMutexPost()
will notice that a higher priority task (i.e., task #1) needs access to the resource and will give the resource to task #1 and perform a context switch to task #1.
µC/OS-II's mutexes consist of three elements: a flag indicating whether the mutex is available (0 or 1), a priority to assign the task that owns the mutex in case a higher priority task attempts to gain access to the mutex, and a list of tasks waiting for the mutex.
µC/OS-II provides six services to access mutexes: OSMutexCreate()
, OSMutexDel()
, OSMutexPend()
, OSMutexPost()
, OSMutexAccept()
and OSMutexQuery()
.
To enable µC/OS-II mutex services, you must set the configuration constants in OS_CFG.H
. Specifically, table 8.1 shows which services are compiled based on the value of configuration constants found in OS_CFG.H
. You should note that NONE of the mailbox services are enabled when OS_MUTEX_EN
is set to 0. To enable specific features (i.e., service) listed in Table 8.1, simply set the configuration constant to 1. You will notice that OSMutexCreate()
, OSMutexPend()
and OSMutexPost()
cannot be individually disabled like the other services. That’s because they are always needed when you enable µC/OS-II mutual exclusion semaphore management.Figure 8.1 shows a flow diagram to illustrate the relationship between tasks and a mutex. A mutex can only be accessed by tasks. Note that the symbology used to represent a mutex is a ‘key’. The ‘key’ symbology shows that the mutex is used to access shared resources.
Creating a Mutex, OSMutexCreate()
A mutex needs to be created before it can be used. Creating a mutex is accomplished by calling OSMutexCreate()
. The initial value of a mutex is always set to 1 indicating that the resource is available. The code to create a mutex is shown in listing 8.2.Figure 8.2 shows the ECB just before returning from OSMutexCreate()
.
Deleting a Mutex, OSMutexDel()
The code to delete a mutex is shown in listing 8.3 and this service is available only if OS_MUTEX_DEL_EN
is set to 1 in OS_CFG.H
. This is a dangerous function to use because multiple tasks could attempt to access a deleted mutex. You should always use this function with great care. Generally speaking, before you would delete a mutex, you should first delete all the tasks that can access the mutex.
Waiting on a Mutex (blocking), OSMutexPend()
The code to wait on a mutex is shown in listing 8.4.
Signaling a Mutex, OSMutexPost()
The code to signal a mutex is shown in listing 8.5.
Getting a Mutex without waiting (non-blocking), OSMutexAccept()
It is possible to obtain a mutex without putting a task to sleep if the mutex is not available. This is accomplished by calling OSMutexAccept()
and the code for this function is shown in listing 8.6.The code that called OSMutexAccept()
will need to examine the returned value. A returned value of 0 indicates that the mutex was not available while a return value of 1 indicates that the mutex was available and the caller can access the resource.
Obtaining the status of a mutex, OSMutexQuery()
OSMutexQuery()
allows your application to take a ‘snapshot’ of an ECB that is used as a mutex. The code for this function is shown in listing 8.7.
Anchor | ||||
---|---|---|---|---|
|
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
OS_EVENT *ResourceMutex;
OS_STK TaskPrio10Stk[1000];
OS_STK TaskPrio15Stk[1000];
OS_STK TaskPrio20Stk[1000];
void main (void)
{
INT8U err;
OSInit(); (1)
---------- Application Initialization ----------
ResourceMutex = OSMutexCreate(9, &err); (2)
OSTaskCreate(TaskPrio10, (void *)0, &TaskPrio10Stk[999], 10); (3)
OSTaskCreate(TaskPrio15, (void *)0, &TaskPrio15Stk[999], 15);
OSTaskCreate(TaskPrio20, (void *)0, &TaskPrio20Stk[999], 20);
---------- Application Initialization ----------
OSStart(); (4)
}
void TaskPrio10 (void *pdata)
{
INT8U err;
pdata = pdata;
while (1) {
--------- Application Code ----------
OSMutexPend(ResourceMutex, 0, &err);
------- Access common resource ------
OSMutexPost(ResourceMutex);
--------- Application Code ----------
}
}
void TaskPrio15 (void *pdata)
{
INT8U err;
pdata = pdata;
while (1) {
--------- Application Code ----------
OSMutexPend(ResourceMutex, 0, &err);
------- Access common resource ------
OSMutexPost(ResourceMutex);
--------- Application Code ----------
}
}
void TaskPrio20 (void *pdata)
{
INT8U err;
pdata = pdata;
while (1) {
--------- Application Code ----------
OSMutexPend(ResourceMutex, 0, &err);
------- Access common resource ------
OSMutexPost(ResourceMutex);
--------- Application Code ----------
}
} |
Panel | ||
---|---|---|
| ||
(1) & (2) As shown in (3) & (4) The three tasks are then created and µC/OS-II is started. |
Suppose that this application has been running for a while and that, at some point, task #3 accesses the common resource first and thus acquires the mutex. Task #3 runs for a while and then gets preempted by task #1. Task #1 needs the resource and thus attempts to acquire the mutex (by calling OSMutexPend()
). In this case, OSMutexPend()
notices that a higher priority task needs the resource and thus raises the priority of task #3 to 9 which forces a context switch back to task #3. Task #3 will proceed and hopefully release the resource quickly. When done with the resource, task #3 will call OSMutexPost()
to release the mutex. OSMutexPost()
will notice that the mutex was owned by a lower priority task that got its priority raised and thus, will return task #3 to it’s original priority. OSMutexPost()
will notice that a higher priority task (i.e., task #1) needs access to the resource and will give the resource to task #1 and perform a context switch to task #1.
µC/OS-II's mutexes consist of three elements: a flag indicating whether the mutex is available (0 or 1), a priority to assign the task that owns the mutex in case a higher priority task attempts to gain access to the mutex, and a list of tasks waiting for the mutex.
µC/OS-II provides six services to access mutexes: OSMutexCreate()
, OSMutexDel()
, OSMutexPend()
, OSMutexPost()
, OSMutexAccept()
and OSMutexQuery()
.
To enable µC/OS-II mutex services, you must set the configuration constants in OS_CFG.H
. Specifically, table 8.1 shows which services are compiled based on the value of configuration constants found in OS_CFG.H
. You should note that NONE of the mailbox services are enabled when OS_MUTEX_EN
is set to 0. To enable specific features (i.e., service) listed in Table 8.1, simply set the configuration constant to 1. You will notice that OSMutexCreate()
, OSMutexPend()
and OSMutexPost()
cannot be individually disabled like the other services. That’s because they are always needed when you enable µC/OS-II mutual exclusion semaphore management.
Anchor | ||||
---|---|---|---|---|
|
Panel | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||||||
|
Figure 8.1 shows a flow diagram to illustrate the relationship between tasks and a mutex. A mutex can only be accessed by tasks. Note that the symbology used to represent a mutex is a ‘key’. The ‘key’ symbology shows that the mutex is used to access shared resources.
Anchor | ||||
---|---|---|---|---|
|
Panel | ||||
---|---|---|---|---|
| ||||
Creating a Mutex, OSMutexCreate()
A mutex needs to be created before it can be used. Creating a mutex is accomplished by calling OSMutexCreate()
. The initial value of a mutex is always set to 1 indicating that the resource is available. The code to create a mutex is shown in listing 8.2.
Anchor | ||||
---|---|---|---|---|
|
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
OS_EVENT *OSMutexCreate (INT8U prio, INT8U *err)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
#endif
OS_EVENT *pevent;
if (OSIntNesting > 0) { (1)
*err = OS_ERR_CREATE_ISR;
return ((OS_EVENT *)0);
}
#if OS_ARG_CHK_EN
if (prio >= OS_LOWEST_PRIO) { (2)
*err = OS_PRIO_INVALID;
return ((OS_EVENT *)0);
}
#endif
OS_ENTER_CRITICAL();
if (OSTCBPrioTbl[prio] != (OS_TCB *)0) { (3)
*err = OS_PRIO_EXIST;
OS_EXIT_CRITICAL();
return ((OS_EVENT *)0);
}
OSTCBPrioTbl[prio] = (OS_TCB *)1; (4)
pevent = OSEventFreeList; (5)
if (pevent == (OS_EVENT *)0) {
OSTCBPrioTbl[prio] = (OS_TCB *)0;
OS_EXIT_CRITICAL();
*err = OS_ERR_PEVENT_NULL;
return (pevent);
}
OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr; (6)
OS_EXIT_CRITICAL();
pevent->OSEventType = OS_EVENT_TYPE_MUTEX; (7)
pevent->OSEventCnt = (prio << 8) | OS_MUTEX_AVAILABLE; (8)
pevent->OSEventPtr = (void *)0; (9)
OSEventWaitListInit(pevent); (10)
*err = OS_NO_ERR;
return (pevent); (11)
}
} |
Panel | ||
---|---|---|
| ||
(1) (2) (3) (4) If an entry is available, (5) (6) The linked list of free ECBs is adjusted to point to the next free ECB. (7) If there was an ECB available, the ECB type is set to (8) It is worth noting that the (9) Because the mutex is being initialized, there are no tasks waiting for it. (10) The wait list is then initialized by calling (11) Finally, |
Figure 8.2 shows the ECB just before returning from OSMutexCreate()
.
Anchor | ||||
---|---|---|---|---|
|
Panel | ||||
---|---|---|---|---|
| ||||
Deleting a Mutex, OSMutexDel()
The code to delete a mutex is shown in listing 8.3 and this service is available only if OS_MUTEX_DEL_EN
is set to 1 in OS_CFG.H
. This is a dangerous function to use because multiple tasks could attempt to access a deleted mutex. You should always use this function with great care. Generally speaking, before you would delete a mutex, you should first delete all the tasks that can access the mutex.
Anchor | ||||
---|---|---|---|---|
|
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
OS_EVENT *OSMutexDel (OS_EVENT *pevent, INT8U opt, INT8U *err)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
#endif
BOOLEAN tasks_waiting;
if (OSIntNesting > 0) { (1)
*err = OS_ERR_DEL_ISR;
return (pevent);
}
#if OS_ARG_CHK_EN
if (pevent == (OS_EVENT *)0) { (2)
*err = OS_ERR_PEVENT_NULL;
return (pevent);
}
if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { (3)
OS_EXIT_CRITICAL();
*err = OS_ERR_EVENT_TYPE;
return (pevent);
}
#endif
OS_ENTER_CRITICAL();
if (pevent->OSEventGrp != 0x00) { (4)
tasks_waiting = TRUE;
} else {
tasks_waiting = FALSE;
}
switch (opt) {
case OS_DEL_NO_PEND:
if (tasks_waiting == FALSE) { (5)
pevent->OSEventType = OS_EVENT_TYPE_UNUSED; (6)
pevent->OSEventPtr = OSEventFreeList; (7)
OSEventFreeList = pevent;
OS_EXIT_CRITICAL();
*err = OS_NO_ERR;
return ((OS_EVENT *)0); (8)
} else {
OS_EXIT_CRITICAL();
*err = OS_ERR_TASK_WAITING;
return (pevent);
}
case OS_DEL_ALWAYS: (9)
while (pevent->OSEventGrp != 0x00) { (10)
OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MUTEX);
}
pevent->OSEventType = OS_EVENT_TYPE_UNUSED; (11)
pevent->OSEventPtr = OSEventFreeList; (12)
OSEventFreeList = pevent;
OS_EXIT_CRITICAL();
if (tasks_waiting == TRUE) { (13)
OS_Sched();
}
*err = OS_NO_ERR;
return ((OS_EVENT *)0); (14)
default:
OS_EXIT_CRITICAL();
*err = OS_ERR_INVALID_OPT;
return (pevent);
}
} |
Panel | ||
---|---|---|
| ||
(1) (2) (3) We then check the arguments passed to it– pevent cannot be a NULL pointer and pevent needs to point to a mutex. (4) Based on the option (i.e., opt) specified in the call, (5) (6) (7) When opt is set to (9) (10) When opt is set to (11) (12) Once all pending tasks are readied, (13) The scheduler is called only if there were tasks waiting on the mutex. (14) You will note that |
Waiting on a Mutex (blocking), OSMutexPend()
The code to wait on a mutex is shown in listing 8.4.
Anchor | ||||
---|---|---|---|---|
|
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
void OSMutexPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
#endif
INT8U pip;
INT8U mprio;
BOOLEAN rdy;
OS_TCB *ptcb;
if (OSIntNesting > 0) { (1)
*err = OS_ERR_PEND_ISR;
return;
}
#if OS_ARG_CHK_EN
if (pevent == (OS_EVENT *)0) { (2)
*err = OS_ERR_PEVENT_NULL;
return;
}
#endif
OS_ENTER_CRITICAL();
#if OS_ARG_CHK_EN
if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { (3)
OS_EXIT_CRITICAL();
*err = OS_ERR_EVENT_TYPE;
return;
}
#endif
(4)
if ((INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_AVAILABLE) {
pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8; (5)
pevent->OSEventCnt |= OSTCBCur->OSTCBPrio; (6)
pevent->OSEventPtr = (void *)OSTCBCur; (7)
OS_EXIT_CRITICAL();
*err = OS_NO_ERR;
return;
}
pip = (INT8U)(pevent->OSEventCnt >> 8); (8)
mprio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8); (9)
ptcb = (OS_TCB *)(pevent->OSEventPtr); (10)
if (ptcb->OSTCBPrio != pip && mprio > OSTCBCur->OSTCBPrio) { (11)
if ((OSRdyTbl[ptcb->OSTCBY] & ptcb->OSTCBBitX) != 0x00) { (12)
(13)
if ((OSRdyTbl[ptcb->OSTCBY] &= ~ptcb->OSTCBBitX) == 0x00) {
OSRdyGrp &= ~ptcb->OSTCBBitY;
}
rdy = TRUE; (14)
} else {
rdy = FALSE; (15)
}
ptcb->OSTCBPrio = pip; (16)
ptcb->OSTCBY = ptcb->OSTCBPrio >> 3;
ptcb->OSTCBBitY = OSMapTbl[ptcb->OSTCBY];
ptcb->OSTCBX = ptcb->OSTCBPrio & 0x07;
ptcb->OSTCBBitX = OSMapTbl[ptcb->OSTCBX];
if (rdy == TRUE) { (17)
OSRdyGrp |= ptcb->OSTCBBitY;
OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
}
OSTCBPrioTbl[pip] = (OS_TCB *)ptcb;
}
OSTCBCur->OSTCBStat |= OS_STAT_MUTEX; (18)
OSTCBCur->OSTCBDly = timeout; (19)
OS_EventTaskWait(pevent); (20)
OS_EXIT_CRITICAL();
OS_Sched(); (21)
OS_ENTER_CRITICAL();
if (OSTCBCur->OSTCBStat & OS_STAT_MUTEX) { (22)
OS_EventTO(pevent); (23)
OS_EXIT_CRITICAL();
*err = OS_TIMEOUT; (24)
return;
}
OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; (25)
OS_EXIT_CRITICAL();
*err = OS_NO_ERR;
} |
Panel | ||
---|---|---|
| ||
(1) Like all µC/OS-II pend calls, (2) & (3) Assuming that the configuration constant (4) & (5) (6) The mutex is available if the lower 8 bits of (7) If the mutex is owned by another task, the calling task needs to be put to sleep until the other task relinquishes the mutex (see (8) & (9) & (10) Before the calling task is put to sleep, (11) If the owner’s priority is lower (a higher number) than the task that calls (12) (13) & (14) If it is, that task will be made no longer ready-to-run at the the owner’s priority and the flag rdy will be set indicating that the mutex owner was ready-to-run. (15) If the task was not ready-to-run, rdy is set accordingly. The reason the flag is set is to determine whether we need to make the task ready-to-run at the new, higher priority (i.e., at the PIP). (16) (17) From this information and the state of the rdy flag, we determine whether the mutex owner needs to be made ready-to-run at the PIP. (18) To put the calling task to sleep, (19) The timeout is also stored in the TCB so that it can be decremented by (20) The actual work of putting the task to sleep is done by (21) Because the calling task is no longer ready-to-run, the scheduler is called to run the next highest priority task that is ready-to-run. When the mutex is signaled (or the timeout period expires) and the task that called (22) (23) & (24) In this case, the task is removed from the wait list for the mutex by calling If the status flag in the task’s TCB doesn’t have the (25) Finally, the link to the ECB is removed. |
Signaling a Mutex, OSMutexPost()
The code to signal a mutex is shown in listing 8.5.
Anchor | ||||
---|---|---|---|---|
|
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
INT8U OSMutexPost (OS_EVENT *pevent)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
#endif
INT8U pip;
INT8U prio;
if (OSIntNesting > 0) { (1)
return (OS_ERR_POST_ISR);
}
#if OS_ARG_CHK_EN
if (pevent == (OS_EVENT *)0) { (2)
return (OS_ERR_PEVENT_NULL);
}
#endif
OS_ENTER_CRITICAL();
pip = (INT8U)(pevent->OSEventCnt >> 8);
prio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8);
#if OS_ARG_CHK_EN
if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { (3)
OS_EXIT_CRITICAL();
return (OS_ERR_EVENT_TYPE);
}
if (OSTCBCur->OSTCBPrio != pip ||
OSTCBCur->OSTCBPrio != prio) { (4)
OS_EXIT_CRITICAL();
return (OS_ERR_NOT_MUTEX_OWNER);
}
#endif
if (OSTCBCur->OSTCBPrio == pip) { (5)
(6)
if ((OSRdyTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0) {
OSRdyGrp &= ~OSTCBCur->OSTCBBitY;
}
OSTCBCur->OSTCBPrio = prio;
OSTCBCur->OSTCBY = prio >> 3;
OSTCBCur->OSTCBBitY = OSMapTbl[OSTCBCur->OSTCBY];
OSTCBCur->OSTCBX = prio & 0x07;
OSTCBCur->OSTCBBitX = OSMapTbl[OSTCBCur->OSTCBX];
OSRdyGrp |= OSTCBCur->OSTCBBitY;
OSRdyTbl[OSTCBCur->OSTCBY] |= OSTCBCur->OSTCBBitX;
OSTCBPrioTbl[prio] = (OS_TCB *)OSTCBCur;
}
OSTCBPrioTbl[pip] = (OS_TCB *)1;
if (pevent->OSEventGrp != 0x00) { (7)
(8)
prio = OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MUTEX);
pevent->OSEventCnt &= 0xFF00; (9)
pevent->OSEventCnt |= prio;
pevent->OSEventPtr = OSTCBPrioTbl[prio];
OS_EXIT_CRITICAL();
OS_Sched(); (10)
return (OS_NO_ERR);
}
pevent->OSEventCnt |= 0x00FF; (11)
pevent->OSEventPtr = (void *)0;
OS_EXIT_CRITICAL();
return (OS_NO_ERR);
} |
Panel | ||
---|---|---|
| ||
(1) Mutual exclusion semaphores must only be used by tasks and thus, a check is performed to make sure that (2) & (3) Assuming that the configuration constant (4) (5) (6) The calling task is removed from the ready list at the PIP and placed in the ready list at the task’s original priority. Note that the TCB fields are recomputed for the original task priority. (7) Next, we check to see if any tasks are waiting on the mutex. There are tasks waiting when the (8) The highest priority task waiting for the mutex will be removed from the wait list by (9) The priority of the new owner is saved in the mutex’s ECB. (10) (11) If there were no tasks waiting on the mutex, the lower 8 bits of |
Getting a Mutex without waiting (non-blocking), OSMutexAccept()
It is possible to obtain a mutex without putting a task to sleep if the mutex is not available. This is accomplished by calling OSMutexAccept()
and the code for this function is shown in listing 8.6.
Anchor | ||||
---|---|---|---|---|
|
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
INT8U OSMutexAccept (OS_EVENT *pevent, INT8U *err)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
#endif
if (OSIntNesting > 0) { (1)
*err = OS_ERR_PEND_ISR;
return (0);
}
#if OS_ARG_CHK_EN
if (pevent == (OS_EVENT *)0) {
*err = OS_ERR_PEVENT_NULL;
return (0);
}
#endif
OS_ENTER_CRITICAL();
#if OS_ARG_CHK_EN
if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) {
OS_EXIT_CRITICAL();
*err = OS_ERR_EVENT_TYPE;
return (0);
}
#endif
OS_ENTER_CRITICAL();
(2)
if ((pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_AVAILABLE) {
pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8; (3)
pevent->OSEventCnt |= OSTCBCur->OSTCBPrio;
pevent->OSEventPtr = (void *)OSTCBCur; (4)
OS_EXIT_CRITICAL();
*err = OS_NO_ERR;
return (1);
}
OS_EXIT_CRITICAL();
*err = OS_NO_ERR;
return (0);
} |
Panel | ||
---|---|---|
| ||
(1) As with the other calls, if (2) (3) & (4) If the mutex is available, |
The code that called OSMutexAccept()
will need to examine the returned value. A returned value of 0 indicates that the mutex was not available while a return value of 1 indicates that the mutex was available and the caller can access the resource.
Obtaining the status of a mutex, OSMutexQuery()
OSMutexQuery()
allows your application to take a ‘snapshot’ of an ECB that is used as a mutex. The code for this function is shown in listing 8.7.
Anchor | ||||
---|---|---|---|---|
|
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
INT8U OSMutexQuery (OS_EVENT *pevent, OS_MUTEX_DATA *pdata)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
#endif
INT8U *psrc;
INT8U *pdest;
if (OSIntNesting > 0) { (1)
return (OS_ERR_QUERY_ISR);
}
#if OS_ARG_CHK_EN
if (pevent == (OS_EVENT *)0) { (2)
return (OS_ERR_PEVENT_NULL);
}
#endif
OS_ENTER_CRITICAL();
#if OS_ARG_CHK_EN
if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { (3)
OS_EXIT_CRITICAL();
return (OS_ERR_EVENT_TYPE);
}
#endif
pdata->OSMutexPIP = (INT8U)(pevent->OSEventCnt >> 8); (4)
pdata->OSOwnerPrio = (INT8U)(pevent->OSEventCnt & 0x00FF);
if (pdata->OSOwnerPrio == 0xFF) {
pdata->OSValue = 1; (5)
} else {
pdata->OSValue = 0; (6)
}
pdata->OSEventGrp = pevent->OSEventGrp; (7)
psrc = &pevent->OSEventTbl[0];
pdest = &pdata->OSEventTbl[0];
#if OS_EVENT_TBL_SIZE > 0
*pdest++ = *psrc++;
#endif
#if OS_EVENT_TBL_SIZE > 1
*pdest++ = *psrc++;
#endif
#if OS_EVENT_TBL_SIZE > 2
*pdest++ = *psrc++;
#endif
#if OS_EVENT_TBL_SIZE > 3
*pdest++ = *psrc++;
#endif
#if OS_EVENT_TBL_SIZE > 4
*pdest++ = *psrc++;
#endif
#if OS_EVENT_TBL_SIZE > 5
*pdest++ = *psrc++;
#endif
#if OS_EVENT_TBL_SIZE > 6
*pdest++ = *psrc++;
#endif
#if OS_EVENT_TBL_SIZE > 7
*pdest = *psrc;
#endif
OS_EXIT_CRITICAL();
return (OS_NO_ERR);
} |
Panel | ||
---|---|---|
| ||
(1) As with all mutex calls, (2) & (3) If the configuration constant (4) First, we extract the Priority Inheritance Priority (PIP) from the upper 8 bits of the (5) Next, we obtain the mutex value from the lower 8 bits of the (6) Otherwise, the mutex value is 0 (i.e., unavailable because it’s owned by a task). (7) Finally, the mutex wait list is copied into the appropriate fields in |
OSMutexQuery()
is passed two arguments: pevent contains a pointer to the mutex which is returned by OSMutexCreate()
when the mutex is created and, pdata which is a pointer to a data structure (OS_MUTEX_DATA
, see uCOS_II.H
) that will hold information about the mutex. Your application will thus need to allocate a variable of type OS_MUTEX_DATA
that will be used to receive the information about the desired mutex. I decided to use a new data structure because the caller should only be concerned with mutex specific data as opposed to the more generic OS_EVENT
data structure. OS_MUTEX_DATA
contains the mutex PIP (Priority Inheritance Priority) (.OSMutexPIP
), the priority of the task owning the mutex (.OSMutexPrio
) and the value of the mutex (.OSMutexValue
) which is set to 1 when the mutex is available and 0 if it’s not. Note that .OSMutexPrio
contains 0xFF if no task owns the mutex. Finally, OS_MUTEX_DATA
contains the list of tasks waiting on the mutex (.OSEventTbl[]
and .OSEventGrp
).
...