任務間的同步依賴於任務間的通信。在μC/OS-II中,使用信號量、互斥信號量、消息郵箱、消息隊列、事件標誌組這些被稱作事件的中間環節來實現任務之間的通信的。爲了把描述事件的數據結構統一起來,μC/OS-II使用叫做事件控制塊ECB的數據結構來描述諸如信號量、互斥信號量、消息郵箱、消息隊列、事件標誌組這些事件。
事件控制塊中包含包括等待任務表在內的所有有關事件的數據 。
#if (OS_EVENT_EN) && (OS_MAX_EVENTS > 0)
typedef struct os_event {
INT8U OSEventType; /* Type of event control block (see OS_EVENT_TYPE_xxxx) */
void *OSEventPtr; /* Pointer to message or queue structure */
INT16U OSEventCnt; /* Semaphore Count (not used if other EVENT type) */
#if OS_LOWEST_PRIO <= 63
INT8U OSEventGrp; /* Group corresponding to tasks waiting for event to occur */
INT8U OSEventTbl[OS_EVENT_TBL_SIZE]; /* List of tasks waiting for event to occur */
#else
INT16U OSEventGrp; /* Group corresponding to tasks waiting for event to occur */
INT16U OSEventTbl[OS_EVENT_TBL_SIZE]; /* List of tasks waiting for event to occur */
#endif
#if OS_EVENT_NAME_SIZE > 1
INT8U OSEventName[OS_EVENT_NAME_SIZE];
#endif
} OS_EVENT;
圖示爲事件控制塊的內存結構圖。
一般地,對於事件控制塊進行如下一些通用操作:
- OS_EventWaitListInit():初始化事件控制塊。
初始化等待任務列表爲全0,沒有任務在等待事件。
void OS_EventWaitListInit (OS_EVENT *pevent)
{
#if OS_LOWEST_PRIO <= 63
INT8U *ptbl;
#else
INT16U *ptbl;
#endif
INT8U i;
pevent->OSEventGrp = 0; /* No task waiting on event */
ptbl = &pevent->OSEventTbl[0];
for (i = 0; i < OS_EVENT_TBL_SIZE; i++) {
*ptbl++ = 0;
}
}
- OS_EventTaskRdy():使任務進入就緒態。
當某個事件發生後,就要使等待任務列表中優先級最高的任務脫離等待,並置於就緒狀態。
INT8U OS_EventTaskRdy (OS_EVENT *pevent, void *pmsg, INT8U msk, INT8U pend_stat)
{
OS_TCB *ptcb;
INT8U y;
INT8U x;
INT8U prio;
#if OS_LOWEST_PRIO > 63
INT16U *ptbl;
#endif
#if OS_LOWEST_PRIO <= 63
y = OSUnMapTbl[pevent->OSEventGrp]; /* Find HPT waiting for message */
x = OSUnMapTbl[pevent->OSEventTbl[y]];
prio = (INT8U)((y << 3) + x); /* Find priority of task getting the msg */
#else
if ((pevent->OSEventGrp & 0xFF) != 0) { /* Find HPT waiting for message */
y = OSUnMapTbl[ pevent->OSEventGrp & 0xFF];
} else {
y = OSUnMapTbl[(pevent->OSEventGrp >> 8) & 0xFF] + 8;
}
ptbl = &pevent->OSEventTbl[y];
if ((*ptbl & 0xFF) != 0) {
x = OSUnMapTbl[*ptbl & 0xFF];
} else {
x = OSUnMapTbl[(*ptbl >> 8) & 0xFF] + 8;
}
prio = (INT8U)((y << 4) + x); /* Find priority of task getting the msg */
#endif
ptcb = OSTCBPrioTbl[prio]; /* Point to this task's OS_TCB */
ptcb->OSTCBDly = 0; /* Prevent OSTimeTick() from readying task */
#if ((OS_Q_EN > 0) && (OS_MAX_QS > 0)) || (OS_MBOX_EN > 0)
ptcb->OSTCBMsg = pmsg; /* Send message directly to waiting task */
#else
pmsg = pmsg; /* Prevent compiler warning if not used */
#endif
ptcb->OSTCBStat &= ~msk; /* Clear bit associated with event type */
ptcb->OSTCBStatPend = pend_stat; /* Set pend status of post or abort */
/* See if task is ready (could be susp'd) */
if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) == OS_STAT_RDY) {
OSRdyGrp |= ptcb->OSTCBBitY; /* Put task in the ready to run list */
OSRdyTbl[y] |= ptcb->OSTCBBitX;
}
OS_EventTaskRemove(ptcb, pevent); /* Remove this task from event wait list */
#if (OS_EVENT_MULTI_EN > 0)
if (ptcb->OSTCBEventMultiPtr != (OS_EVENT **)0) { /* Remove this task from events' wait lists */
OS_EventTaskRemoveMulti(ptcb, ptcb->OSTCBEventMultiPtr);
ptcb->OSTCBEventPtr = (OS_EVENT *)pevent;/* Return event as first multi-pend event ready*/
}
#endif
return (prio);
}
- OS_EventTaskWait():使任務進入等待某事件發生狀態
當某個任務要等待一個事件發生時,相應OSSemPend()、OSMutexPend()、OSMboxPend()或OSQPend()函數會調用OSEventTaskWait()函數將當前任務從任務就緒表中刪除,並放到相應事件的事件控制塊的等待任務列表中。
void OS_EventTaskWait (OS_EVENT *pevent)
{
INT8U y;
OSTCBCur->OSTCBEventPtr = pevent; /* Store ptr to ECB in TCB */
pevent->OSEventTbl[OSTCBCur->OSTCBY] |= OSTCBCur->OSTCBBitX; /* Put task in waiting list */
pevent->OSEventGrp |= OSTCBCur->OSTCBBitY;
y = OSTCBCur->OSTCBY; /* Task no longer ready */
OSRdyTbl[y] &= ~OSTCBCur->OSTCBBitX;
if (OSRdyTbl[y] == 0) {
OSRdyGrp &= ~OSTCBCur->OSTCBBitY; /* Clear event grp bit if this was only task pending */
}
}
- OS_EventTaskRemove() : 刪除任務對某時間的等待狀態
void OS_EventTaskRemove (OS_TCB *ptcb,
OS_EVENT *pevent)
{
INT8U y;
y = ptcb->OSTCBY;
pevent->OSEventTbl[y] &= ~ptcb->OSTCBBitX; /* Remove task from wait list */
if (pevent->OSEventTbl[y] == 0) {
pevent->OSEventGrp &= ~ptcb->OSTCBBitY;
}
}