Chapter 6 Intertask Communication & Sysnchronization Semaphores, message mailboxes, and message queue Figure 6.1 use of event control blocks (ECB) ISR Signal (1) Wait ECB (2) Task Timeout (3) Task Signal (1) A Wait ECB (2) Task Timeout (3) ISR Task Signal Wait B ECB Task Signal Task Wait/Signal Wait Task Timeout (4) Task Wait/Signal (4) ECB Timeout C Event Control Blocks • Each semaphore, mailbox, and queue is assigned an ECB typedef struct { void *OSEventPtr; /* Ptr to message or queue structure */ INT8U OSEventTbl[OS_EVENT_TBL_SIZE]; /* Wait list for event to occur INT16U OSEventCnt; /* Count (when event is a semaphore) */ INT8U OSEventType; /* Event type */ INT8U OSEventGrp; /* Group for wait list */ } OS_EVENT; • OSEventPtr: only used when the ECB is assigned to a mailbox or a queue • OSEventTbl[] and OSEventGrp are similar to OSRdyTbl[ and OSRdyGrp, respectively • OSEventCnt: used to hold the semaphore count • OSEventType: contains the type associated with the ECB – OS_EVENT_SEM, OS_EVENT_TYPE_MBOX, OS_EVENT_TYPE_Q */ Figure 6.2 Wait list for task waiting for an event to occur .OSEventGrp 7 6 5 4 3 2 1 0 .OSEventTbl[OS_LOWEST_PRIO / 8 + 1] Highest Priority Task Waiting X [0] 7 1 0 [1] 15 14 13 12 11 10 9 8 [2] 23 22 21 20 19 18 17 16 [3] 31 30 29 28 27 26 25 24 [4] 39 38 37 36 35 34 33 32 [5] 47 46 45 44 43 42 41 40 [6] 55 54 53 52 51 50 49 48 [7] 63 62 61 60 59 58 57 56 6 5 4 3 2 Priority of task waiting for the event to occur. Task's Priority 0 0 Y Y Y X X X Lowest Priority Task (Idle Task, can NEVER be waiting) Bit position in .OSEventTbl[OS_LOWEST_PRIO / 8 + 1] Bit position in .OSEventGrp and Index into .OSEventTbl[OS_LOWEST_PRIO / 8 + 1] Y Making a task wait for an event pevent->OSEventGrp |= OSMapTbl[prio >> 3]; pevent->OSEventTbl[prio >> 3] |= OSMapTbl[prio & 0x07]; Removing a task from a wait list if ((pevent->OSEventTbl[prio >> 3] &= ~OSMapTbl[prio & 0x07]) == 0) { pevent->OSEventGrp &= ~OSMapTbl[prio >> 3]; } Finding the highest priority task waiting for the event y = OSUnMapTbl[pevent->OSEventGrp]; x = OSUnMapTbl[pevent->OSEventTbl[y]]; prio = (y << 3) + x; Figure 6.3 List of free ECBs OS_EVENT OSEventFreeList 0 OS_MAX_EVENTS • The number of ECBs to allocate depends on the number of semaphores, mailboxes, and queues needed for your application • When OSInit() is called, all ECBs are linked in a singly linked list – The list of free ECBs • Four common operations can be performed on ECBs – – – – Initialize an ECB Make a task ready Make a task wait for an event Make a task ready because a timeout occurred while waiting for an event • Four functions have been created to performs these operations – – – – OSEventWaitListInit() OSEventTaskRdy() OSEventWait() OSEventTO() Initializing an ECB OSEventWaitListInit() • Is called by OSSemCreate(), OSMboxCreate (), OSQCreate () – No task is waiting on the ECB void OSEventWaitListInit (OS_EVENT *pevent) { INT8U i; pevent->OSEventGrp = 0x00; for (i = 0; i < OS_EVENT_TBL_SIZE; i++) { pevent->OSEventTbl[i] = 0x00; } } Making a task ready OSEventTaskRdy() • This function is called by – OSSemPost(), OSMbosPost(), OSQPost(), and OSQPostFront() • Removes the highest priority task (HPT) from the wait list of the ECB and makes this task ready to run void OSEventTaskRdy (OS_EVENT *pevent, void *msg, INT8U msk) { OS_TCB *ptcb; INT8U x; INT8U y; INT8U bitx; INT8U bity; INT8U prio; OSEventTaskRdy (cont’d) y = OSUnMapTbl[pevent->OSEventGrp]; (1) bity = OSMapTbl[y]; (2) x = OSUnMapTbl[pevent->OSEventTbl[y]]; (3) bitx = OSMapTbl[x]; (4) prio = (INT8U)((y << 3) + x); (5) if ((pevent->OSEventTbl[y] &= ~bitx) == 0) { (6) pevent->OSEventGrp &= ~bity; } ptcb = OSTCBPrioTbl[prio]; (7) ptcb->OSTCBDly = 0; (8) ptcb->OSTCBEventPtr = (OS_EVENT *)0; (9) #if (OS_Q_EN && (OS_MAX_QS >= 2)) || OS_MBOX_EN ptcb->OSTCBMsg = msg; (10) #else msg = msg; #endif ptcb->OSTCBStat &= ~msk; (Semaphore,mail box, mail queue) if (ptcb->OSTCBStat == OS_STAT_RDY) { (12) OSRdyGrp |= bity; (13) OSRdyTbl[y] |= bitx; } } (11) Figure 6.4 Making a task ready to run .OSEventGrp 7 6 5 4 3 2 1 0 .OSEventTbl[] x bity (2) (3) [0] 7 1 0 [1] 15 14 13 12 11 10 9 8 [2] 23 22 21 20 19 18 17 16 [3] 31 30 29 28 27 26 25 24 [4] 39 38 37 36 35 34 33 32 [5] 47 46 45 44 43 42 41 40 [6] 55 54 53 52 51 50 49 48 [7] 63 62 61 60 59 58 57 56 6 5 4 bitx (4) 3 2 y (1) Making a task wait for an event OSEventTaskWait() • Called by OSSemPend(), OSMboxPend, and OSQPend() when a task must wait on an ECB • OSEventTaskWait() removes the current task from the ready list and places it in the wait list of the ECB void OSEventTaskWait (OS_EVENT *pevent) { OSTCBCur->OSTCBEventPtr = pevent; if ((OSRdyTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0) { OSRdyGrp &= ~OSTCBCur->OSTCBBitY; } pevent->OSEventTbl[OSTCBCur->OSTCBY] |= OSTCBCur->OSTCBBitX; pevent->OSEventGrp |= OSTCBCur->OSTCBBitY; } (1) (2) (3) Making a task ready becase of a timeout OSEventTO() • Called by OSSemPend(), OSMboxPend(), OSQPend() when a task has been made ready to run by OSTimeTick() • OSEventTO() must remove the task from the wait list of the ECB and mark the task as being ready void OSEventTO (OS_EVENT *pevent) { if ((pevent->OSEventTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0) { (1) pevent->OSEventGrp &= ~OSTCBCur->OSTCBBitY; } OSTCBCur->OSTCBStat = OS_STAT_RDY; (2) OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; (3) } Semaphores • Create a semaphore by calling OSSemCreate() • The initial count of the semaphore can be 0 to 65535 – Use to signal the occurrence of one ore more event, the init value is 0 (flag) – Use to access a shared resource, the init value is set to 1 (binary) (key) • Five services will access semaphore: – OSSemCreate(), OSSemPend(), OSSemPost(), OSSemAccept(), OSSemQuery() Figure 6.5 Relationships between tasks, ISRs, and a semaphore OSSemCreate() Task OSSemPost() N OR ISR OSSemPost() OSSemAccept() N OSSemPend() OSSemAccept() OSSemQuery() Task Creating a Semaphore OSSemCreate() OS_EVENT *OSSemCreate (INT16U cnt) { OS_EVENT *pevent; OS_ENTER_CRITICAL(); pevent = OSEventFreeList; (1) if (OSEventFreeList != (OS_EVENT *)0) { (2) OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr; } OS_EXIT_CRITICAL(); if (pevent != (OS_EVENT *)0) { (3) pevent->OSEventType = OS_EVENT_TYPE_SEM; (4) pevent->OSEventCnt = cnt; (5) OSEventWaitListInit(pevent); (6) } return (pevent); (7) } Waiting on a Semaphore OSSemPend() void OSSemPend (OS_EVENT *pevent, INT16U timeout, INT8U *err) { OS_ENTER_CRITICAL(); if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { (1) OS_EXIT_CRITICAL(); *err = OS_ERR_EVENT_TYPE; } if (pevent->OSEventCnt > 0) { (2) pevent->OSEventCnt--; (3) OS_EXIT_CRITICAL(); *err = OS_NO_ERR; } else if (OSIntNesting > 0) { (4) OS_EXIT_CRITICAL(); *err = OS_ERR_PEND_ISR; } else { OSTCBCur->OSTCBStat |= OS_STAT_SEM; (5) OSTCBCur->OSTCBDly = timeout; (6) OSEventTaskWait(pevent); (7) OS_EXIT_CRITICAL(); OSSched(); (8) OS_ENTER_CRITICAL(); if (OSTCBCur->OSTCBStat & OS_STAT_SEM) { (9) OSEventTO(pevent); (10) OS_EXIT_CRITICAL(); *err = OS_TIMEOUT; } else { OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; (11) OS_EXIT_CRITICAL(); *err = OS_NO_ERR; } } } Signaling a Semaphore OSSemPost() INT8U OSSemPost (OS_EVENT *pevent) { OS_ENTER_CRITICAL(); if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { OS_EXIT_CRITICAL(); return (OS_ERR_EVENT_TYPE); } if (pevent->OSEventGrp) { (2) OSEventTaskRdy(pevent, (void *)0, OS_STAT_SEM); OS_EXIT_CRITICAL(); OSSched(); (4) return (OS_NO_ERR); } else { if (pevent->OSEventCnt < 65535) { pevent->OSEventCnt++; (5) OS_EXIT_CRITICAL(); return (OS_NO_ERR); } else { OS_EXIT_CRITICAL(); return (OS_SEM_OVF); } } } (1) (3) Getting a Semaphore without Waiting OSSemAccept() • To obtain a semaphore without putting a task to sleep if the semaphore is not available INT16U OSSemAccept (OS_EVENT *pevent) { INT16U cnt; OS_ENTER_CRITICAL(); if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { OS_EXIT_CRITICAL(); return (0); } cnt = pevent->OSEventCnt; (2) if (cnt > 0) { (3) pevent->OSEventCnt--; (4) } OS_EXIT_CRITICAL(); return (cnt); (5) } (1) Obaining the status of a semaphore OSSemQuery() • Allow APs to take a snapshot of an ECB • Two arguments are required – Pevent: pointer to the semaphore – Pdata pointer to a data structure which will receive the information about the desired semaphore INT8U OSSemQuery (OS_EVENT *pevent, OS_SEM_DATA *pdata) { INT8U i; INT8U *psrc; INT8U *pdest; OS_ENTER_CRITICAL(); if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { OS_EXIT_CRITICAL(); return (OS_ERR_EVENT_TYPE); } pdata->OSEventGrp = pevent->OSEventGrp; (2) psrc = &pevent->OSEventTbl[0]; pdest = &pdata->OSEventTbl[0]; for (i = 0; i < OS_EVENT_TBL_SIZE; i++) { *pdest++ = *psrc++; } pdata->OSCnt = pevent->OSEventCnt; (3) OS_EXIT_CRITICAL(); return (OS_NO_ERR); } (1) Message Mailboxes • Allow a task or an ISR to send a pointer-sized variable to another task • Five services to access mailboxes – OSMboxCreate(), OSMboxPend(), OSMboxPost(), OSMboxAccept(), OSMboxQuery Figure 6.6 Relationships between tasks, ISRs, and a message mailbox OSMboxCreate() Task OSMboxPost() OSMboxPend() OSMboxAccept() OSMboxQuery() ISR OSMboxPost() OSMboxAccept() Mailbox Message Task Creating a Mailbox -- OSMboxCreate() • Similar to OSSemCreate() – Use OSEventPtr to instead of the OSEventCnt • Return a pointer to the ECB, such as mailbox handle OS_EVENT *OSMboxCreate (void *msg) { OS_EVENT *pevent; OS_ENTER_CRITICAL(); pevent = OSEventFreeList; if (OSEventFreeList != (OS_EVENT *)0) { OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr; } OS_EXIT_CRITICAL(); if (pevent != (OS_EVENT *)0) { pevent->OSEventType = OS_EVENT_TYPE_MBOX; (1) pevent->OSEventPtr = msg; (2) OSEventWaitListInit(pevent); } return (pevent); (3) } Waiting for a Message at a Mailbox OSMboxPend() • Similar to OSSemPend() void *OSMboxPend (OS_EVENT *pevent, INT16U timeout, INT8U *err) { void *msg; OS_ENTER_CRITICAL(); if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) { (1) OS_EXIT_CRITICAL(); *err = OS_ERR_EVENT_TYPE; return ((void *)0); } msg = pevent->OSEventPtr; if (msg != (void *)0) { (2) pevent->OSEventPtr = (void *)0; (3) OS_EXIT_CRITICAL(); *err = OS_NO_ERR; } else if (OSIntNesting > 0) { (4) OS_EXIT_CRITICAL(); *err = OS_ERR_PEND_ISR; Waiting for a message to arrive at a mailbox (cont’d) } else { OSTCBCur->OSTCBStat |= OS_STAT_MBOX; (5) OSTCBCur->OSTCBDly = timeout; OSEventTaskWait(pevent); OS_EXIT_CRITICAL(); OSSched(); OS_ENTER_CRITICAL(); if ((msg = OSTCBCur->OSTCBMsg) != (void *)0) { (6) OSTCBCur->OSTCBMsg = (void *)0; OSTCBCur->OSTCBStat = OS_STAT_RDY; OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; OS_EXIT_CRITICAL(); *err = OS_NO_ERR; } else if (OSTCBCur->OSTCBStat & OS_STAT_MBOX) { (7) OSEventTO(pevent); (8) OS_EXIT_CRITICAL(); msg = (void *)0; (9) *err = OS_TIMEOUT; } else { msg = pevent->OSEventPtr; (10) pevent->OSEventPtr = (void *)0; OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; (11) OS_EXIT_CRITICAL(); *err = OS_NO_ERR; } } return (msg); } Sending a Message to a Mailbox OSMboxPost() INT8U OSMboxPost (OS_EVENT *pevent, void *msg) { OS_ENTER_CRITICAL(); if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) { OS_EXIT_CRITICAL(); return (OS_ERR_EVENT_TYPE); } if (pevent->OSEventGrp) { (2) OSEventTaskRdy(pevent, msg, OS_STAT_MBOX); OS_EXIT_CRITICAL(); OSSched(); (4) return (OS_NO_ERR); } else { if (pevent->OSEventPtr != (void *)0) { (5) OS_EXIT_CRITICAL(); return (OS_MBOX_FULL); } else { pevent->OSEventPtr = msg; (6) OS_EXIT_CRITICAL(); return (OS_NO_ERR); } } } (1) (3) Getting a Message without Waiting OSMboxAccept() void *OSMboxAccept (OS_EVENT *pevent) { void *msg; OS_ENTER_CRITICAL(); if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) { OS_EXIT_CRITICAL(); return ((void *)0); } msg = pevent->OSEventPtr; (2) if (msg != (void *)0) { (3) pevent->OSEventPtr = (void *)0; (4) } OS_EXIT_CRITICAL(); return (msg); (5) } (1) Obtaining the status of a Mailbox OSMboxQuery() INT8U OSMboxQuery (OS_EVENT *pevent, OS_MBOX_DATA *pdata) { INT8U i; INT8U *psrc; INT8U *pdest; OS_ENTER_CRITICAL(); if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) { OS_EXIT_CRITICAL(); return (OS_ERR_EVENT_TYPE); } pdata->OSEventGrp = pevent->OSEventGrp; (2) psrc = &pevent->OSEventTbl[0]; pdest = &pdata->OSEventTbl[0]; for (i = 0; i < OS_EVENT_TBL_SIZE; i++) { *pdest++ = *psrc++; } pdata->OSMsg = pevent->OSEventPtr; (3) OS_EXIT_CRITICAL(); return (OS_NO_ERR); } (1) Using a Mailbox as a Binary Semaphore • Initializing the mailbox with a non-NULL pointer (ex void *1) as a binary semaphore OS_EVENT *MboxSem; void Task1 (void *pdata) { INT8U err; for (;;) { OSMboxPend(MboxSem, 0, &err); /* Obtain access to resource(s) */ . . /* Task has semaphore, access resource(s) */ . OSMboxPost(MboxSem, (void )1); /* Release access to resource(s) */ } } Using a Mailbox instead of OSTimeDly() OS_EVENT *MboxTimeDly; void Task1 (void *pdata) { INT8U err; for (;;) { OSMboxPend(MboxTimeDly, TIMEOUT, &err); /* Delay task */ . . /* Code executed after time delay */ . } } void Task2 (void *pdata) { INT8U err; for (;;) { OSMboxPost(MboxTimeDly, (void *)1); /* Cancel delay for Task1 */ . . } } • • Task1() resumes execution after the time period expires if no message is received Task2() post a “dummy” message to the mailbox before the timeout expires. – Same as calling OSTimeDlyResume() Message Queue • Seven services to access message queues – OSQCreate(), OSQPend(), OSQPost(), OSQPostFront(), OSQAccept(), OSQFlush(), and OSQQuery Figure 6.7 Relationships between tasks, ISRs, and a message queue OSQCreate() Task ISR OSQPost() OSQPostFront() OSQFlush() OSQPost() OSQPostFront() OSQFlush() OSQAccept() N OSQPend() OSQAccept() OSQQuery() Queue Message Task Figure 6.8 Data structures used in a message queue OS_EVENT ( 1 ) OSEv entGrp 7 6 5 4 3 2 1 0 OSEv entTbl[] 63 62 61 60 59 58 57 56 OSEventCnt OSEv entPtr Field not used! OS_Q ( 2 ) void *MsgTbl[] OSQPtr OSQStart OSQSize OSQOut OSQIn OSQEnd OSQEntries ( 3 ) OSQEntries OSQSize Array allocated by your application Figure 6.9 List of free queue control blocks OS_MAX_QS OSQFreeList OSQPtr OSQStart OSQSize OSQOut OSQIn OSQEnd OSQEntries OSQPtr OSQStart OSQSize OSQOut OSQIn OSQEnd OSQEntries OSQPtr OSQStart OSQSize OSQOut OSQIn OSQEnd OSQEntries 0 OS_Q Figure 6.10 A message queue is a circular buffer of pointers . O S Q S t a r t . O (5) . O . O S Q O u t Q O u t S Q E n d . O (5) (2) S . (4) O S Q S i z e (3) . O S Q E (3) n t r i e S Q I s (1) Pointer to message n OS_EVENT *OSQCreate (void **start, INT16U size) { OS_EVENT *pevent; OS_Q *pq; OS_ENTER_CRITICAL(); pevent = OSEventFreeList; (1) if (OSEventFreeList != (OS_EVENT *)0) { OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr; (2) } OS_EXIT_CRITICAL(); if (pevent != (OS_EVENT *)0) { OS_ENTER_CRITICAL(); pq = OSQFreeList; (3) if (OSQFreeList != (OS_Q *)0) { OSQFreeList = OSQFreeList->OSQPtr; } OS_EXIT_CRITICAL(); if (pq != (OS_Q *)0) { pq->OSQStart = start; (4) pq->OSQEnd = &start[size]; pq->OSQIn = start; pq->OSQOut = start; pq->OSQSize = size; pq->OSQEntries = 0; pevent->OSEventType = OS_EVENT_TYPE_Q; (5) pevent->OSEventPtr = pq; (6) OSEventWaitListInit(pevent); (7) } else { OS_ENTER_CRITICAL(); pevent->OSEventPtr = (void *)OSEventFreeList; (8) OSEventFreeList = pevent; OS_EXIT_CRITICAL(); pevent = (OS_EVENT *)0; } } return (pevent); (9) } Creating a queue, OSQCreate() Waiting for a Message at a Queue, OSQPend() void *OSQPend (OS_EVENT *pevent, INT16U timeout, INT8U *err) { void *msg; OS_Q *pq; OS_ENTER_CRITICAL(); if (pevent->OSEventType != OS_EVENT_TYPE_Q) { (1) OS_EXIT_CRITICAL(); *err = OS_ERR_EVENT_TYPE; return ((void *)0); } pq = pevent->OSEventPtr; if (pq->OSQEntries != 0) { (2) msg = *pq->OSQOut++; (3) pq->OSQEntries--; (4) if (pq->OSQOut == pq->OSQEnd) { (5) pq->OSQOut = pq->OSQStart; (6) } OS_EXIT_CRITICAL(); *err = OS_NO_ERR; } else if (OSIntNesting > 0) { (7) OS_EXIT_CRITICAL(); *err = OS_ERR_PEND_ISR; } else { OSTCBCur->OSTCBStat |= OS_STAT_Q; OSTCBCur->OSTCBDly = timeout; OSEventTaskWait(pevent); OS_EXIT_CRITICAL(); OSSched(); (9) OS_ENTER_CRITICAL(); if ((msg = OSTCBCur->OSTCBMsg) != (void *)0) { OSTCBCur->OSTCBMsg = (void *)0; OSTCBCur->OSTCBStat = OS_STAT_RDY; OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; OS_EXIT_CRITICAL(); *err = OS_NO_ERR; } else if (OSTCBCur->OSTCBStat & OS_STAT_Q) { OSEventTO(pevent); (13) OS_EXIT_CRITICAL(); msg = (void *)0; (14) *err = OS_TIMEOUT; } else { msg = *pq->OSQOut++; (15) pq->OSQEntries--; if (pq->OSQOut == pq->OSQEnd) { pq->OSQOut = pq->OSQStart; } OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; OS_EXIT_CRITICAL(); *err = OS_NO_ERR; } } return (msg); (17) } (8) (10) (11) (12) (16) 6.23 Depositing a message in a queue (FIFO) INT8U OSQPost (OS_EVENT *pevent, void *msg) { OS_Q *pq; OS_ENTER_CRITICAL(); if (pevent->OSEventType != OS_EVENT_TYPE_Q) { (1) OS_EXIT_CRITICAL(); return (OS_ERR_EVENT_TYPE); } if (pevent->OSEventGrp) { (2) OSEventTaskRdy(pevent, msg, OS_STAT_Q); (3) OS_EXIT_CRITICAL(); OSSched(); return (OS_NO_ERR); } else { pq = pevent->OSEventPtr; if (pq->OSQEntries >= pq->OSQSize) { (4) OS_EXIT_CRITICAL(); return (OS_Q_FULL); } else { *pq->OSQIn++ = msg; (5) pq->OSQEntries++; if (pq->OSQIn == pq->OSQEnd) { pq->OSQIn = pq->OSQStart; } OS_EXIT_CRITICAL(); } return (OS_NO_ERR); } } Sending a message to a queue (LIFO), OSQPostFront() INT8U OSQPostFront (OS_EVENT *pevent, void *msg) { OS_Q *pq; OS_ENTER_CRITICAL(); if (pevent->OSEventType != OS_EVENT_TYPE_Q) { OS_EXIT_CRITICAL(); return (OS_ERR_EVENT_TYPE); } if (pevent->OSEventGrp) { OSEventTaskRdy(pevent, msg, OS_STAT_Q); OS_EXIT_CRITICAL(); OSSched(); return (OS_NO_ERR); } else { pq = pevent->OSEventPtr; if (pq->OSQEntries >= pq->OSQSize) { OS_EXIT_CRITICAL(); return (OS_Q_FULL); } else { if (pq->OSQOut == pq->OSQStart) { (1) pq->OSQOut = pq->OSQEnd; (2) } pq->OSQOut--; (3) *pq->OSQOut = msg; pq->OSQEntries++; OS_EXIT_CRITICAL(); } return (OS_NO_ERR); } } Getting a message without waiting, OSQAccept() void *OSQAccept (OS_EVENT *pevent) { void *msg; OS_Q *pq; OS_ENTER_CRITICAL(); if (pevent->OSEventType != OS_EVENT_TYPE_Q) { OS_EXIT_CRITICAL(); return ((void *)0); } pq = pevent->OSEventPtr; if (pq->OSQEntries != 0) { (2) msg = *pq->OSQOut++; (3) pq->OSQEntries--; if (pq->OSQOut == pq->OSQEnd) { pq->OSQOut = pq->OSQStart; } } else { msg = (void *)0; (4) } OS_EXIT_CRITICAL(); return (msg); } (1) Flushing a queue, OSQFlush() INT8U OSQFlush (OS_EVENT *pevent) { OS_Q *pq; OS_ENTER_CRITICAL(); if (pevent->OSEventType != OS_EVENT_TYPE_Q) { OS_EXIT_CRITICAL(); return (OS_ERR_EVENT_TYPE); } pq = pevent->OSEventPtr; pq->OSQIn = pq->OSQStart; (2) pq->OSQOut = pq->OSQStart; pq->OSQEntries = 0; OS_EXIT_CRITICAL(); return (OS_NO_ERR); } (1) Using a message queue when reading analog inputs ( Analog Inputs MUX 2 ADC ) ( 3 ) ( 4 ) Task Queue O S Q ( O S Q ( P 5 o s t ( P 1 ) ) ) T i m e o u e t n d ( ) Using a queue as a counting semaphore OS_EVENT *QSem; void *QMsgTbl[N_RESOURCES] void main (void) { OSInit(); . QSem = OSQCreate(&QMsgTbl[0], N_RESOURCES); for (i = 0; i < N_RESOURCES; i++) { OSQPost(Qsem, (void *)1); } . OSTaskCreate(Task1, .., .., ..); . OSStart(); } void Task1 (void *pdata) { INT8U err; for (;;) { OSQPend(&QSem, 0, &err); /* Obtain access to resource(s) */ . . /* Task has semaphore, access resource(s) */ . OSMQPost(QSem, (void )1); /* Release access to resource(s) */ } } Obtaining the status of a queue, OSQQuery() INT8U OSQQuery (OS_EVENT *pevent, OS_Q_DATA *pdata) { OS_Q *pq; INT8U i; INT8U *psrc; INT8U *pdest; OS_ENTER_CRITICAL(); if (pevent->OSEventType != OS_EVENT_TYPE_Q) { OS_EXIT_CRITICAL(); return (OS_ERR_EVENT_TYPE); } pdata->OSEventGrp = pevent->OSEventGrp; (2) psrc = &pevent->OSEventTbl[0]; pdest = &pdata->OSEventTbl[0]; for (i = 0; i < OS_EVENT_TBL_SIZE; i++) { *pdest++ = *psrc++; } pq = (OS_Q *)pevent->OSEventPtr; if (pq->OSQEntries > 0) { (3) pdata->OSMsg = pq->OSQOut; (4) } else { pdata->OSMsg = (void *)0; (5) } pdata->OSNMsgs = pq->OSQEntries; (6) pdata->OSQSize = pq->OSQSize; OS_EXIT_CRITICAL(); return (OS_NO_ERR); } (1)