it's this section's map.函數
事件初始化代碼在操做系統初始化函數OS_Init中被調用,其函數名爲OS_InitEventList,定義以下post
1 static void OS_InitEventList (void) 2 { 3 #if (OS_EVENT_EN) && (OS_MAX_EVENTS > 0) 4 #if (OS_MAX_EVENTS > 1) 5 INT16U i; 6 OS_EVENT *pevent1; 7 OS_EVENT *pevent2; 8 9 10 OS_MemClr((INT8U *)&OSEventTbl[0], sizeof(OSEventTbl)); /* Clear the event table */ 11 pevent1 = &OSEventTbl[0]; 12 pevent2 = &OSEventTbl[1]; 13 for (i = 0; i < (OS_MAX_EVENTS - 1); i++) { /* Init. list of free EVENT control blocks */ 14 pevent1->OSEventType = OS_EVENT_TYPE_UNUSED; 15 pevent1->OSEventPtr = pevent2; 16 #if OS_EVENT_NAME_SIZE > 1 17 pevent1->OSEventName[0] = '?'; /* Unknown name */ 18 pevent1->OSEventName[1] = OS_ASCII_NUL; 19 #endif 20 pevent1++; 21 pevent2++; 22 } 23 pevent1->OSEventType = OS_EVENT_TYPE_UNUSED; 24 pevent1->OSEventPtr = (OS_EVENT *)0; 25 #if OS_EVENT_NAME_SIZE > 1 26 pevent1->OSEventName[0] = '?'; 27 pevent1->OSEventName[1] = OS_ASCII_NUL; 28 #endif 29 OSEventFreeList = &OSEventTbl[0]; 30 #else 31 OSEventFreeList = &OSEventTbl[0]; /* Only have ONE event control block */ 32 OSEventFreeList->OSEventType = OS_EVENT_TYPE_UNUSED; 33 OSEventFreeList->OSEventPtr = (OS_EVENT *)0; 34 #if OS_EVENT_NAME_SIZE > 1 35 OSEventFreeList->OSEventName[0] = '?'; /* Unknown name */ 36 OSEventFreeList->OSEventName[1] = OS_ASCII_NUL; 37 #endif 38 #endif 39 #endif 40 }
line 10清空了以前的事件表this
line 13~ line 22對除了最後一個以外的全部ECB進行了初始化,並構建了單向鏈表。spa
line 23~ line24使最後一個ECB指向了空地址0.操作系統
最後line 29將表頭地址賦給全局變量OSEventFreeList.指針
當創建一個事件或消息時,如信號量的創建函數OSSemCreate等,須要對事件等待表進行初始化。事件等待表初始化函數實現對制定任務塊中事件等待表和時間等待組清零,可悲操做系統的其它函數調用。code
1 #if (OS_EVENT_EN) 2 void OS_EventWaitListInit (OS_EVENT *pevent) 3 { 4 #if OS_LOWEST_PRIO <= 63 5 INT8U *ptbl; 6 #else 7 INT16U *ptbl; 8 #endif 9 INT8U i; 10 11 12 pevent->OSEventGrp = 0; /* No task waiting on event */ 13 ptbl = &pevent->OSEventTbl[0]; 14 15 for (i = 0; i < OS_EVENT_TBL_SIZE; i++) { 16 *ptbl++ = 0; 17 } 18 } 19 #endif
總的來講,這個函數的功能即把事件等待表再次初始化了一遍,作的和第一個函數中line 13~line 22中同樣的工做,最後一個OSEventTbl被無視。blog
可是我不知道爲何要再Init一遍。隊列
這三塊我以爲與以前任務管理部分的操做有些相似,因此放一起講。類比在看完源碼後給出。事件
當任務等待事件發生,並得到ECB後,須要在ECB中標記任務在等待事件的發生。才能夠在事件發生時取消任務的阻塞。將任務在ECB中進行登記的函數是OS_EventTaskWait,參數是事件控制塊的指針。
與OS_EventWaitListInit相似,OS_EventTaskWait在任務調用信號量、郵箱等時間等待函數時被對應函數調用。由於任務優先級能夠經過當前TCB指針OSTCBCur獲得,所以沒有做爲參數傳遞。
源碼以下
1 #if (OS_EVENT_EN) 2 void OS_EventTaskWait (OS_EVENT *pevent) 3 { 4 INT8U y; 5 6 7 OSTCBCur->OSTCBEventPtr = pevent; /* Store ptr to ECB in TCB */ 8 9 pevent->OSEventTbl[OSTCBCur->OSTCBY] |= OSTCBCur->OSTCBBitX; /* Put task in waiting list */ 10 pevent->OSEventGrp |= OSTCBCur->OSTCBBitY; 11 12 y = OSTCBCur->OSTCBY; /* Task no longer ready */ 13 OSRdyTbl[y] &= ~OSTCBCur->OSTCBBitX; 14 if (OSRdyTbl[y] == 0) { 15 OSRdyGrp &= ~OSTCBCur->OSTCBBitY; /* Clear event grp bit if this was only task pending */ 16 } 17 } 18 #endif
line 7中:在TCB的OSTCBEventPtr域存儲ECB指針,之後經過該任務的TCB能夠直接找到這個事件的ECB。
以後作了兩件事——標記和取消標記。聽聞這裏的操做和就緒表中設置就緒標誌的徹底一致的,那便先放着吧。
這個函數與上一個函數是相反的操做。當一個事件因爲某種緣由再也不須要等待事件時,就須要在事件的等待表中取消該事件的等待標誌。
1 #if (OS_EVENT_EN) 2 void OS_EventTaskRemove (OS_TCB *ptcb, 3 OS_EVENT *pevent) 4 { 5 INT8U y; 6 7 8 y = ptcb->OSTCBY; 9 pevent->OSEventTbl[y] &= ~ptcb->OSTCBBitX; /* Remove task from wait list */ 10 if (pevent->OSEventTbl[y] == 0) { 11 pevent->OSEventGrp &= ~ptcb->OSTCBBitY; 12 } 13 } 14 #endif
line 9:在事件等待表中刪除事件等待標誌
line 10:若該行已沒有任務等待
line 11:刪除事件等待組的事件等待標誌
任務由於等待時間而在ECB中登記本身的等待,當事件發生時,若是該任務是事件等待表中優先級最高的任務,就緒就取消等待而回到就緒狀態。
源碼以下:
1 #if (OS_EVENT_EN) 2 INT8U OS_EventTaskRdy (OS_EVENT *pevent, void *pmsg, INT8U msk, INT8U pend_stat) 3 { 4 OS_TCB *ptcb; 5 INT8U y; 6 INT8U x; 7 INT8U prio; 8 #if OS_LOWEST_PRIO > 63 9 INT16U *ptbl; 10 #endif 11 12 13 #if OS_LOWEST_PRIO <= 63 14 y = OSUnMapTbl[pevent->OSEventGrp]; /* Find HPT waiting for message */ 15 x = OSUnMapTbl[pevent->OSEventTbl[y]]; 16 prio = (INT8U)((y << 3) + x); /* Find priority of task getting the msg */ 17 #else 18 if ((pevent->OSEventGrp & 0xFF) != 0) { /* Find HPT waiting for message */ 19 y = OSUnMapTbl[ pevent->OSEventGrp & 0xFF]; 20 } else { 21 y = OSUnMapTbl[(pevent->OSEventGrp >> 8) & 0xFF] + 8; 22 } 23 ptbl = &pevent->OSEventTbl[y]; 24 if ((*ptbl & 0xFF) != 0) { 25 x = OSUnMapTbl[*ptbl & 0xFF]; 26 } else { 27 x = OSUnMapTbl[(*ptbl >> 8) & 0xFF] + 8; 28 } 29 prio = (INT8U)((y << 4) + x); /* Find priority of task getting the msg */ 30 #endif 31 32 ptcb = OSTCBPrioTbl[prio]; /* Point to this task's OS_TCB */ 33 ptcb->OSTCBDly = 0; /* Prevent OSTimeTick() from readying task */ 34 #if ((OS_Q_EN > 0) && (OS_MAX_QS > 0)) || (OS_MBOX_EN > 0) 35 ptcb->OSTCBMsg = pmsg; /* Send message directly to waiting task */ 36 #else 37 pmsg = pmsg; /* Prevent compiler warning if not used */ 38 #endif 39 ptcb->OSTCBStat &= ~msk; /* Clear bit associated with event type */ 40 ptcb->OSTCBStatPend = pend_stat; /* Set pend status of post or abort */ 41 /* See if task is ready (could be susp'd) */ 42 if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) == OS_STAT_RDY) { 43 OSRdyGrp |= ptcb->OSTCBBitY; /* Put task in the ready to run list */ 44 OSRdyTbl[y] |= ptcb->OSTCBBitX; 45 } 46 47 OS_EventTaskRemove(ptcb, pevent); /* Remove this task from event wait list */ 48 #if (OS_EVENT_MULTI_EN > 0) 49 if (ptcb->OSTCBEventMultiPtr != (OS_EVENT **)0) { /* Remove this task from events' wait lists */ 50 OS_EventTaskRemoveMulti(ptcb, ptcb->OSTCBEventMultiPtr); 51 ptcb->OSTCBEventPtr = (OS_EVENT *)pevent;/* Return event as first multi-pend event ready*/ 52 } 53 #endif 54 55 return (prio); 56 } 57 #endif
幾個參數的解析以下:
line 13~ line 30在事件等待表和事件等待組中找到最高優先級的等待任務的優先級(line 17~ line 30是任務數多於63的狀況,書上未提);
line 32 根據優先級在優先級指針表中找到該任務的TCB指針;
line 33~ line 40對TCB的相關參數進行賦值;
line 42~ line 45判斷任務是否被掛起,若是未被掛起就將任務就緒,完成從阻塞態到就緒態的轉換;
line 47 調用OS_EventTaskRemove函數在ECB的事件等待表中刪除該任務;
line 55返回任務優先級。
這三個函數的關係如圖(略簡陋)
Done