Chapter 6 Intertask Communication & Sysnchronization

advertisement
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)
Download