日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關咨詢
選擇下列產(chǎn)品馬上在線溝通
服務時間:8:30-17:00
你可能遇到了下面的問題
關閉右側工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
鴻蒙輕內(nèi)核M核源碼分析系列十二事件Event

想了解更多內(nèi)容,請訪問:

公司專注于為企業(yè)提供成都做網(wǎng)站、網(wǎng)站建設、微信公眾號開發(fā)、商城網(wǎng)站建設,小程序開發(fā),軟件按需網(wǎng)站建設等一站式互聯(lián)網(wǎng)企業(yè)服務。憑借多年豐富的經(jīng)驗,我們會仔細了解各客戶的需求而做出多方面的分析、設計、整合,為客戶設計出具風格及創(chuàng)意性的商業(yè)解決方案,成都創(chuàng)新互聯(lián)更提供一系列網(wǎng)站制作和網(wǎng)站推廣的服務。

和華為官方合作共建的鴻蒙技術社區(qū)

https://harmonyos.

事件(Event)是一種任務間通信的機制,可用于任務間的同步。多任務環(huán)境下,任務之間往往需要同步操作,一個等待即是一個同步。事件可以提供一對多、多對多的同步操作。本文通過分析鴻蒙輕內(nèi)核事件模塊的源碼,深入掌握事件的使用。

接下來,我們看下事件的結構體,事件初始化,事件常用操作的源代碼。

1、事件結構體定義和常用宏定義

1.1 事件結構體定義

在文件kernel\include\los_event.h定義的事件控制塊結構體為EVENT_CB_S,結構體源代碼如下,結構體成員的解釋見注釋部分。

 
 
 
 
  1. typedef struct tagEvent { 
  2.     UINT32 uwEventID;        /**< 事件ID,每一位標識一種事件類型 */ 
  3.     LOS_DL_LIST stEventList; /**< 讀取事件的任務鏈表 */ 
  4. } EVENT_CB_S, *PEVENT_CB_S; 

 1.2 事件常用宏定義

在讀事件時,可以選擇讀取模式。讀取模式由如下幾個宏定義:

所有事件(LOS_WAITMODE_AND):

邏輯與,基于接口傳入的事件類型掩碼eventMask,只有這些事件都已經(jīng)發(fā)生才能讀取成功,否則該任務將阻塞等待或者返回錯誤碼。

任一事件(LOS_WAITMODE_OR):

邏輯或,基于接口傳入的事件類型掩碼eventMask,只要這些事件中有任一種事件發(fā)生就可以讀取成功,否則該任務將阻塞等待或者返回錯誤碼。

清除事件(LOS_WAITMODE_CLR):

這是一種附加讀取模式,需要與所有事件模式或任一事件模式結合使用(LOS_WAITMODE_AND | LOS_WAITMODE_CLR或 LOS_WAITMODE_OR | LOS_WAITMODE_CLR)。在這種模式下,當設置的所有事件模式或任一事件模式讀取成功后,會自動清除事件控制塊中對應的事件類型位。

 
 
 
 
  1. #define LOS_WAITMODE_AND                   (4) 
  2.  
  3.   #define LOS_WAITMODE_OR                    (2) 
  4.  
  5.   #define LOS_WAITMODE_CLR                   (1) 

 2、事件常用操作

2.1 初始化事件

在使用事件前,必須使用函數(shù)UINT32 LOS_EventInit(PEVENT_CB_S eventCB)來初始化事件,需要的參數(shù)是結構體指針變量PEVENT_CB_S eventCB。分析下代碼,⑴處表示傳入的參數(shù)不能為空,否則返回錯誤碼。⑵處把事件編碼.uwEventID初始化為0,然后初始化雙向循環(huán)鏈表.stEventList,用于掛載讀取事件的任務。

 
 
 
 
  1. LITE_OS_SEC_TEXT_INIT UINT32 LOS_EventInit(PEVENT_CB_S eventCB) 
  2. ⑴  if (eventCB == NULL) { 
  3.         return LOS_ERRNO_EVENT_PTR_NULL; 
  4.     } 
  5. ⑵  eventCB->uwEventID = 0; 
  6.     LOS_ListInit(&eventCB->stEventList); 
  7.     OsHookCall(LOS_HOOK_TYPE_EVENT_INIT); 
  8.     return LOS_OK; 

 2.2 校驗事件掩碼

我們可以使用函數(shù)UINT32 LOS_EventPoll(UINT32 *eventId, UINT32 eventMask, UINT32 mode)來校驗事件掩碼,需要的參數(shù)為事件結構體的事件編碼eventId、用戶傳入的待校驗的事件掩碼eventMask及讀取模式mode,返回用戶傳入的事件是否發(fā)生: 返回值為0時,表示用戶預期的事件沒有發(fā)生,否則表示用戶期望的事件發(fā)生。

我們看下源碼,⑴處先檢查傳入?yún)?shù)的合法性,事件編碼不能為空。然后執(zhí)行⑵處的代碼進行校驗。如果是任一事件讀取模式,接下來的判斷不等于表示至少有一個事件發(fā)生了,返回值ret就表示哪些事件發(fā)生了。⑶如果是所有事情讀取模式,當邏輯與運算*eventId & eventMask還等于eventMask時,表示期望的事件全部發(fā)生了,返回值ret就表示哪些事件發(fā)生了。⑷處當ret不為0,期望的事件發(fā)生,并且是清除事件讀取模式時,需要把已經(jīng)發(fā)生的事情進行清除。看來,這個函數(shù)不僅僅是查詢事件有沒有發(fā)生,還會有更新事件編碼的動作。

 
 
 
 
  1. LITE_OS_SEC_TEXT UINT32 LOS_EventPoll(UINT32 *eventID, UINT32 eventMask, UINT32 mode) 
  2.     UINT32 ret = 0; 
  3.     UINT32 intSave; 
  4.  
  5. ⑴  if (eventID == NULL) { 
  6.         return LOS_ERRNO_EVENT_PTR_NULL; 
  7.     } 
  8.     intSave = LOS_IntLock(); 
  9. ⑵  if (mode & LOS_WAITMODE_OR) { 
  10.         if ((*eventID & eventMask) != 0) { 
  11.             ret = *eventID & eventMask; 
  12.         } 
  13.     } else { 
  14. ⑶      if ((eventMask != 0) && (eventMask == (*eventID & eventMask))) { 
  15.             ret = *eventID & eventMask; 
  16.         } 
  17.     } 
  18. ⑷  if (ret && (mode & LOS_WAITMODE_CLR)) { 
  19.         *eventID = *eventID & ~(ret); 
  20.     } 
  21.     LOS_IntRestore(intSave); 
  22.     return ret; 

2.3 讀/寫事件

2.3.1 讀取指定事件類型

我們可以使用函數(shù)LOS_EventRead()來讀取事件,需要4個參數(shù)。eventCB是初始化好的事件結構體,eventMask表示需要讀取的事件掩碼,mode是上文說明過的讀取模式,timeout是讀取超時,單位是Tick。函數(shù)返回0時,表示期望的事件沒有發(fā)生,讀取事件失敗,進入阻塞。返回非0時表示期望的事件發(fā)生了,成功讀取事件。下面我們分析下函數(shù)的源碼來看看如何讀取事件的。

⑴處調(diào)用函數(shù)OsEventReadParamCheck()進行基礎的校驗,比如第25位保留不能使用,事件掩碼eventMask不能為零,讀取模式組合是否合法。⑵處表示不能中斷中讀取事件。⑶處調(diào)用校驗函數(shù)OsEventPoll()檢查事件eventMask是否發(fā)生。如果事件發(fā)生ret不為0,成功讀取直接返回。ret為0,事件沒有發(fā)生時,執(zhí)行⑷,如果超時時間timeout為0,調(diào)用者不能等待時,直接返回。⑸如果鎖任務調(diào)度時,不能讀取事件,返回錯誤碼。

⑹更新當前任務的阻塞的事件掩碼.eventMask和事件讀取模式.eventMode。執(zhí)行⑺調(diào)用函數(shù)OsSchedTaskWait更改當前任務的狀態(tài)為阻塞狀態(tài),掛載到事件的任務阻塞鏈表上。如果timeout不是永久等待,還會把任務設置為OS_TASK_STATUS_PEND_TIME狀態(tài)并設置等待時間。⑻處觸發(fā)任務調(diào)度,后續(xù)程序需要等到讀取到事件才會繼續(xù)執(zhí)行。

⑼如果等待時間超時,事件還不可讀,本任務讀取不到指定的事件時,返回錯誤碼。如果可以讀取到指定的事件時,執(zhí)行⑽,檢查事件eventMask是否發(fā)生,然后返回結果值。

 
 
 
 
  1. LITE_OS_SEC_TEXT UINT32 LOS_EventRead(PEVENT_CB_S eventCB, UINT32 eventMask, UINT32 mode, UINT32 timeOut) 
  2.     UINT32 ret; 
  3.     UINT32 intSave; 
  4.     LosTaskCB *runTsk = NULL; 
  5.  
  6. ⑴  ret = OsEventReadParamCheck(eventCB, eventMask, mode); 
  7.     if (ret != LOS_OK) { 
  8.         return ret; 
  9.     } 
  10.  
  11. ⑵  if (OS_INT_ACTIVE) { 
  12.         return LOS_ERRNO_EVENT_READ_IN_INTERRUPT; 
  13.     } 
  14.     intSave = LOS_IntLock(); 
  15. ⑶  ret = LOS_EventPoll(&(eventCB->uwEventID), eventMask, mode); 
  16.     OsHookCall(LOS_HOOK_TYPE_EVENT_READ, eventCB, eventMask, mode); 
  17.     if (ret == 0) { 
  18. ⑷      if (timeOut == 0) { 
  19.             LOS_IntRestore(intSave); 
  20.             return ret; 
  21.         } 
  22.  
  23. ⑸      if (g_losTaskLock) { 
  24.             LOS_IntRestore(intSave); 
  25.             return LOS_ERRNO_EVENT_READ_IN_LOCK; 
  26.         } 
  27.         runTsk = g_losTask.runTask; 
  28. ⑹      runTsk->eventMask = eventMask; 
  29.         runTsk->eventMode = mode; 
  30. ⑺      OsSchedTaskWait(&eventCB->stEventList, timeOut); 
  31.         LOS_IntRestore(intSave); 
  32. ⑻      LOS_Schedule(); 
  33.  
  34. ⑼      intSave = LOS_IntLock(); 
  35.         if (runTsk->taskStatus & OS_TASK_STATUS_TIMEOUT) { 
  36.             runTsk->taskStatus &= ~OS_TASK_STATUS_TIMEOUT; 
  37.             LOS_IntRestore(intSave); 
  38.             return LOS_ERRNO_EVENT_READ_TIMEOUT; 
  39.         } 
  40.  
  41. ⑽      ret = LOS_EventPoll(&eventCB->uwEventID, eventMask, mode); 
  42.     } 
  43.  
  44.     LOS_IntRestore(intSave); 
  45.     return ret; 

 2.3.2 寫入指定的事件類型

我們可以使用函數(shù)UINT32 LOS_EventWrite(PEVENT_CB_S eventCB, UINT32 events)來寫入指定的事件類型。代碼如下所示:

下面通過分析源碼來看看如何寫入事件類型的。⑴處代碼把事件結構體的事件掩碼和要寫入的事件類型events進行邏輯或計算,來完成事件的寫入。⑵如果等待事件的任務鏈表不為空,需要處理寫入事件后是否有任務能讀取到相應的事件。⑶處for循環(huán)依次遍歷事件阻塞鏈表上的任務,⑷獲取下一個任務nextTask。⑸處

分不同的讀取模式判斷事件是否符合任務resumedTask讀取事件的要求,如果滿足讀取事件,執(zhí)行⑹設置退出標記exitFlag,然后調(diào)用函數(shù)OsSchedTaskWake()把讀取事件的任務更改狀態(tài)并放入就緒隊列,繼續(xù)執(zhí)行⑺,遍歷事件的阻塞任務鏈表中的每一個任務。⑻如果有任務讀取到事件,需要觸發(fā)任務調(diào)度。

 
 
 
 
  1. LITE_OS_SEC_TEXT UINT32 LOS_EventWrite(PEVENT_CB_S eventCB, UINT32 events) 
  2.     LosTaskCB *resumedTask = NULL; 
  3.     LosTaskCB *nextTask = (LosTaskCB *)NULL; 
  4.     UINT32 intSave; 
  5.     UINT8 exitFlag = 0; 
  6.     if (eventCB == NULL) { 
  7.         return LOS_ERRNO_EVENT_PTR_NULL; 
  8.     } 
  9.     if ((eventCB->stEventList.pstNext == NULL) || (eventCB->stEventList.pstPrev == NULL)) { 
  10.         return LOS_ERRNO_EVENT_NOT_INITIALIZED; 
  11.     } 
  12.     if (events & LOS_ERRTYPE_ERROR) { 
  13.         return LOS_ERRNO_EVENT_SETBIT_INVALID; 
  14.     } 
  15.     intSave = LOS_IntLock(); 
  16. ⑴  eventCB->uwEventID |= events; 
  17.     OsHookCall(LOS_HOOK_TYPE_EVENT_WRITE, eventCB); 
  18. ⑵  if (!LOS_ListEmpty(&eventCB->stEventList)) { 
  19. ⑶      for (resumedTask = LOS_DL_LIST_ENTRY((&eventCB->stEventList)->pstNext, LosTaskCB, pendList); 
  20.              &resumedTask->pendList != (&eventCB->stEventList);) { 
  21. ⑷          nextTask = LOS_DL_LIST_ENTRY(resumedTask->pendList.pstNext, LosTaskCB, pendList); 
  22.  
  23. ⑸          if (((resumedTask->eventMode & LOS_WAITMODE_OR) && (resumedTask->eventMask & events) != 0) || 
  24.                 ((resumedTask->eventMode & LOS_WAITMODE_AND) && 
  25.                  ((resumedTask->eventMask & eventCB->uwEventID) == resumedTask->eventMask))) { 
  26. ⑹              exitFlag = 1; 
  27.  
  28.                 OsSchedTaskWake(resumedTask); 
  29.             } 
  30. ⑺          resumedTask = nextTask; 
  31.         } 
  32.  
  33.         if (exitFlag == 1) { 
  34.             LOS_IntRestore(intSave); 
  35. ⑻          LOS_Schedule(); 
  36.             return LOS_OK; 
  37.         } 
  38.     } 
  39.  
  40.     LOS_IntRestore(intSave); 
  41.     return LOS_OK; 

2.4 清除事件

我們可以使用函數(shù)UINT32 LOS_EventClear(PEVENT_CB_S eventCB, UINT32 eventMask)來清除指定的事件類型,下面通過分析源碼看看如何清除事件類型的。

函數(shù)參數(shù)為事件結構體eventCB和要清除的事件類型eventMask。清除事件時首先會進行結構體參數(shù)是否為空的校驗,這些比較簡單。⑴處把事件結構體的事件掩碼和要清除的事件類型eventMask進行邏輯與計算,來完成事件的清理。

 
 
 
 
  1. LITE_OS_SEC_TEXT_MINOR UINT32 LOS_EventClear(PEVENT_CB_S eventCB, UINT32 eventMask) 
  2.     UINT32 intSave; 
  3.     if (eventCB == NULL) { 
  4.         return LOS_ERRNO_EVENT_PTR_NULL; 
  5.     } 
  6.     intSave = LOS_IntLock(); 
  7. ⑴  eventCB->uwEventID &= eventMask; 
  8.     LOS_IntRestore(intSave); 
  9.     OsHookCall(LOS_HOOK_TYPE_EVENT_CLEAR, eventCB); 
  10.     return LOS_OK; 

 2.5 銷毀事件

我們可以使用函數(shù)UINT32 LOS_EventDestroy(PEVENT_CB_S eventCB)來銷毀指定的事件控制塊,下面通過分析源碼看看如何銷毀事件的。

函數(shù)參數(shù)為事件結構體,銷毀事件時首先會進行結構體參數(shù)是否為空的校驗,這些比較簡單。⑴處如果事件的任務阻塞鏈表不為空,則不能銷毀事件。⑵把事件結構體的讀取事件的任務鏈表stEventList設置為空,完成事件的銷毀。

 
 
 
 
  1. LITE_OS_SEC_TEXT_INIT UINT32 LOS_EventDestroy(PEVENT_CB_S eventCB) 
  2.     UINT32 intSave; 
  3.     if (eventCB == NULL) { 
  4.         return LOS_ERRNO_EVENT_PTR_NULL; 
  5.     } 
  6.     intSave = LOS_IntLock(); 
  7.  
  8. ⑴  if (!LOS_ListEmpty(&eventCB->stEventList)) { 
  9.         LOS_IntRestore(intSave); 
  10.         return LOS_ERRNO_EVENT_SHOULD_NOT_DESTORY; 
  11.     } 
  12. ⑵  eventCB->stEventList.pstNext = (LOS_DL_LIST *)NULL; 
  13.     eventCB->stEventList.pstPrev = (LOS_DL_LIST *)NULL; 
  14.     LOS_IntRestore(intSave); 
  15.     OsHookCall(LOS_HOOK_TYPE_EVENT_DESTROY); 
  16.     return LOS_OK; 

 小結

本文帶領大家一起剖析了鴻蒙輕內(nèi)核的事件模塊的源代碼,包含事件的結構體、事件初始化、事件創(chuàng)建刪除、申請釋放等。

想了解更多內(nèi)容,請訪問:

和華為官方合作共建的鴻蒙技術社區(qū)

https://harmonyos.


分享名稱:鴻蒙輕內(nèi)核M核源碼分析系列十二事件Event
URL鏈接:http://www.dlmjj.cn/article/dpgppsi.html