4.1 事件管理程序

it's  this section's map.函數

 

一、事件控制塊(ECB)初始化OS_InitEventList

事件初始化代碼在操做系統初始化函數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.指針

 

二、事件等待表初始化OS_EventWaitListInit

當創建一個事件或消息時,如信號量的創建函數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一遍。隊列

 

三、設置事件等待、取消事件等待、將等待的事件就緒

這三塊我以爲與以前任務管理部分的操做有些相似,因此放一起講。類比在看完源碼後給出。事件

 

3.1 設置事件等待OS_EventTaskWait

當任務等待事件發生,並得到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。

以後作了兩件事——標記和取消標記。聽聞這裏的操做和就緒表中設置就緒標誌的徹底一致的,那便先放着吧。

 

3.2 取消事件等待OS_EventTaskRemove

這個函數與上一個函數是相反的操做。當一個事件因爲某種緣由再也不須要等待事件時,就須要在事件的等待表中取消該事件的等待標誌。

 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:刪除事件等待組的事件等待標誌

 

3.3 將等待事件的任務就緒

任務由於等待時間而在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

 幾個參數的解析以下:

  • pevent:對應ECB指針;
  • pmsg:消息指針。當使用諸如消息隊列或者消息郵箱的消息服務的時候使用該指針。當時是信號量或其餘事件的時候不使用該指針;
  • msk:清除狀態位的掩碼;使用該參數的目的是不須要操做系統斷定是何種事件發生而增長運行成本。
  • pend_stat:表示等待結束、任務就緒的緣由(以宏來表示);
  • 返回任務優先級(任務優先級seems to be unique)。

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

相關文章
相關標籤/搜索