精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

鴻蒙輕內核M核源碼分析系列十三 消息隊列Queue

開發 前端
本文帶領大家一起剖析了鴻蒙輕內核的隊列模塊的源代碼,包含隊列的結構體、隊列池初始化、隊列創建刪除、讀寫消息等。

[[403723]]

想了解更多內容,請訪問:

51CTO和華為官方合作共建的鴻蒙技術社區

https://harmonyos.51cto.com

隊列(Queue)是一種常用于任務間通信的數據結構。任務能夠從隊列里面讀取消息,當隊列中的消息為空時,掛起讀取任務;當隊列中有新消息時,掛起的讀取任務被喚醒并處理新消息。任務也能夠往隊列里寫入消息,當隊列已經寫滿消息時,掛起寫入任務;當隊列中有空閑消息節點時,掛起的寫入任務被喚醒并寫入消息。如果將讀隊列和寫隊列的超時時間設置為0,則不會掛起任務,接口會直接返回,這就是非阻塞模式。消息隊列提供了異步處理機制,允許將一個消息放入隊列,但不立即處理。同時隊列還有緩沖消息的作用。

本文通過分析鴻蒙輕內核隊列模塊的源碼,掌握隊列使用上的差異。

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

1、隊列結構體定義和常用宏定義

1.1 隊列結構體定義

在文件kernel\include\los_queue.h中定義隊列控制塊結構體為LosQueueCB,結構體源代碼如下。隊列狀態.queueState取值OS_QUEUE_UNUSED、OS_QUEUE_INUSED,其他結構體成員見注釋部分。

  1. typedef struct { 
  2.     UINT8 *queue;      /**< 隊列內存空間的指針 */ 
  3.     UINT16 queueState; /**< 隊列的使用狀態 */ 
  4.     UINT16 queueLen;   /**< 隊列長度,即消息數量 */ 
  5.     UINT16 queueSize;  /**< 消息節點大小 */ 
  6.     UINT16 queueID;    /**< 隊列編號  */ 
  7.     UINT16 queueHead;  /**< 消息頭節點位置 */ 
  8.     UINT16 queueTail;  /**< 消息尾節點位置 */ 
  9.     UINT16 readWriteableCnt[OS_READWRITE_LEN]; /**< 2維數組,可讀、可寫的消息數量, 0:可讀, 1:可寫 */ 
  10.     LOS_DL_LIST readWriteList[OS_READWRITE_LEN]; /**< 2維雙向鏈表數組,阻塞讀、寫任務的雙向鏈表, 0:讀鏈表, 1:寫鏈表 */ 
  11.     LOS_DL_LIST memList; /**< 內存節點雙向鏈表 */ 
  12. } LosQueueCB; 

 1.2 隊列常用宏定義

系統支持創建多少隊列是根據開發板情況使用宏LOSCFG_BASE_IPC_QUEUE_LIMIT定義的,每一個隊列queueID是queueID類型的,取值為[0,LOSCFG_BASE_IPC_QUEUE_LIMIT),表示隊列池中各個隊列的編號。

⑴處的宏從隊列池中獲取指定隊列編號QueueID對應的隊列控制塊。⑵處根據雙向鏈表節點readWriteList[OS_QUEUE_WRITE]獲取隊列控制塊內存地址。

  1. ⑴    #define GET_QUEUE_HANDLE(QueueID) (((LosQueueCB *)g_allQueue) + (QueueID)) 
  2.  
  3. ⑵    #define GET_QUEUE_LIST(ptr) LOS_DL_LIST_ENTRY(ptr, LosQueueCB, readWriteList[OS_QUEUE_WRITE]) 

 另外,隊列中還提供了比較重要的隊列讀取消息操作相關的枚舉和宏。枚舉QueueReadWrite區分隊列的讀和寫,枚舉QueueHeadTail區分隊列的首和尾,枚舉QueuePointOrNot區分讀寫消息時是使用值還是指針。

隊列的操作類型使用3比特位的數字來表示,見宏OS_QUEUE_OPERATE_TYPE的定義,其中高1位表示讀寫數值還是讀寫指針地址,中1位表示隊首還是隊尾,低1位表示讀取還是寫入。枚舉和宏的定義如下:

  1. typedef enum { 
  2.     OS_QUEUE_READ, 
  3.     OS_QUEUE_WRITE 
  4. } QueueReadWrite; 
  5.  
  6. typedef enum { 
  7.     OS_QUEUE_HEAD, 
  8.     OS_QUEUE_TAIL 
  9. } QueueHeadTail; 
  10.  
  11. typedef enum { 
  12.     OS_QUEUE_NOT_POINT, 
  13.     OS_QUEUE_POINT 
  14. } QueuePointOrNot; 
  15.  
  16. #define OS_QUEUE_OPERATE_TYPE(ReadOrWrite, HeadOrTail, PointOrNot)  \ 
  17.                 (((UINT32)(PointOrNot) << 2) | ((UINT32)(HeadOrTail) << 1) | (ReadOrWrite)) 
  18. #define OS_QUEUE_READ_WRITE_GET(type) ((type) & (0x01)) 
  19. #define OS_QUEUE_READ_HEAD     (OS_QUEUE_READ | (OS_QUEUE_HEAD << 1)) 
  20. #define OS_QUEUE_READ_TAIL     (OS_QUEUE_READ | (OS_QUEUE_TAIL << 1)) 
  21. #define OS_QUEUE_WRITE_HEAD    (OS_QUEUE_WRITE | (OS_QUEUE_HEAD << 1)) 
  22. #define OS_QUEUE_WRITE_TAIL    (OS_QUEUE_WRITE | (OS_QUEUE_TAIL << 1)) 
  23. #define OS_QUEUE_OPERATE_GET(type) ((type) & (0x03)) 
  24. #define OS_QUEUE_IS_POINT(type)    ((type) & (0x04)) 
  25. #define OS_QUEUE_IS_READ(type)     (OS_QUEUE_READ_WRITE_GET(type) == OS_QUEUE_READ) 
  26. #define OS_QUEUE_IS_WRITE(type)    (OS_QUEUE_READ_WRITE_GET(type) == OS_QUEUE_WRITE) 
  27. #define OS_READWRITE_LEN           2 

 2、隊列初始化

隊列在內核中默認開啟,用戶可以通過宏LOSCFG_BASE_IPC_QUEUE進行關閉。開啟隊列的情況下,在系統啟動時,在kernel\src\los_init.c中調用OsQueueInit()進行隊列模塊初始化。下面,我們分析下隊列初始化的代碼。

⑴為隊列申請內存,如果申請失敗,則返回錯誤。⑵初始化雙向循環鏈表g_freeQueueList,維護未使用的隊列。⑶循環每一個隊列進行初始化,為每一個隊列節點指定索引queueID,并把隊列節點插入未使用隊列雙向鏈表g_freeQueueList。代碼上可以看出,掛在未使用隊列雙向鏈表上的節點是每個隊列控制塊的寫阻塞任務鏈表節點.readWriteList[OS_QUEUE_WRITE]。

  1. LITE_OS_SEC_TEXT_INIT UINT32 OsQueueInit(VOID) 
  2.     LosQueueCB *queueNode = NULL
  3.     UINT16 index
  4.  
  5.     if (LOSCFG_BASE_IPC_QUEUE_LIMIT == 0) { 
  6.         return LOS_ERRNO_QUEUE_MAXNUM_ZERO; 
  7.     } 
  8.  
  9. ⑴  g_allQueue = (LosQueueCB *)LOS_MemAlloc(m_aucSysMem0, LOSCFG_BASE_IPC_QUEUE_LIMIT * sizeof(LosQueueCB)); 
  10.     if (g_allQueue == NULL) { 
  11.         return LOS_ERRNO_QUEUE_NO_MEMORY; 
  12.     } 
  13.  
  14.     (VOID)memset_s(g_allQueue, LOSCFG_BASE_IPC_QUEUE_LIMIT * sizeof(LosQueueCB), 
  15.                    0, LOSCFG_BASE_IPC_QUEUE_LIMIT * sizeof(LosQueueCB)); 
  16.  
  17. ⑵  LOS_ListInit(&g_freeQueueList); 
  18. ⑶  for (index = 0; index < LOSCFG_BASE_IPC_QUEUE_LIMIT; index++) { 
  19.         queueNode = ((LosQueueCB *)g_allQueue) + index
  20.         queueNode->queueID = index
  21.         LOS_ListTailInsert(&g_freeQueueList, &queueNode->readWriteList[OS_QUEUE_WRITE]); 
  22.     } 
  23.  
  24.     return LOS_OK; 

 3、隊列常用操作

3.1 隊列創建

創建隊列函數是LOS_QueueCreate(),先看看該函數的參數:queueName是隊列名稱,實際上并沒有使用。len是隊列中消息的數量,queueID是隊列編號,flags保留未使用。maxMsgSize是隊列中每條消息的最大大小。

我們分析下創建隊列的代碼。⑴處對參數進行校驗,隊列編碼不能為空,隊列消息長度不能太大,隊列消息數量和隊列消息大小不能為0。⑵處計算消息的實際最大大小msgSize,即maxMsgSize + sizeof(UINT32)消息最大大小再加4個字節,在消息的最后4個字節用來保存消息的實際長度。然后調用⑶處函數LOS_MemAlloc()為對隊列動態申請內存,如果內存申請失敗,則返回錯誤碼。

⑷處判斷g_freeQueueList是否為空,如果沒有可以使用的隊列,釋放前文申請的內存。⑸處如果g_freeQueueList不為空,則獲取第一個可用的隊列節點,接著從雙向鏈表g_freeQueueList中刪除,然后調用宏GET_QUEUE_LIST獲取LosQueueCB *queueCB,初始化創建的隊列信息,包含隊列的長度.queueLen、消息大小.queueSize,隊列內存空間.queue,消息狀態.queueState,可讀的數量.readWriteableCnt[OS_QUEUE_READ]為0,可寫的數量readWriteableCnt[OS_QUEUE_WRITE]為隊列消息長度len,隊列頭位置.queueHead和尾位置.queueTail為0。

⑹初始化雙向鏈表.readWriteList[OS_QUEUE_READ],阻塞在這個隊列上的讀消息任務會掛在這個鏈表上。初始化雙向鏈表.readWriteList[OS_QUEUE_WRITE],阻塞在這個隊列上的寫消息任務會掛在這個鏈表上。初始化雙向鏈表.memList。⑺賦值給輸出參數*queueID,后續程序使用這個隊列編號對隊列進行其他操作。

  1. LITE_OS_SEC_TEXT_INIT UINT32 LOS_QueueCreate(CHAR *queueName, 
  2.                                              UINT16 len, 
  3.                                              UINT32 *queueID, 
  4.                                              UINT32 flags, 
  5.                                              UINT16 maxMsgSize) 
  6.     LosQueueCB *queueCB = NULL
  7.     UINT32 intSave; 
  8.     LOS_DL_LIST *unusedQueue = NULL
  9.     UINT8 *queue = NULL
  10.     UINT16 msgSize; 
  11.  
  12.     (VOID)queueName; 
  13.     (VOID)flags; 
  14.  
  15. ⑴  if (queueID == NULL) { 
  16.         return LOS_ERRNO_QUEUE_CREAT_PTR_NULL; 
  17.     } 
  18.  
  19.     if (maxMsgSize > (OS_NULL_SHORT - sizeof(UINT32))) { 
  20.         return LOS_ERRNO_QUEUE_SIZE_TOO_BIG; 
  21.     } 
  22.  
  23.     if ((len == 0) || (maxMsgSize == 0)) { 
  24.         return LOS_ERRNO_QUEUE_PARA_ISZERO; 
  25.     } 
  26. ⑵  msgSize = maxMsgSize + sizeof(UINT32); 
  27.  
  28.     /* Memory allocation is time-consuming, to shorten the time of disable interrupt, 
  29.        move the memory allocation to here. */ 
  30. ⑶  queue = (UINT8 *)LOS_MemAlloc(m_aucSysMem0, len * msgSize); 
  31.     if (queue == NULL) { 
  32.         return LOS_ERRNO_QUEUE_CREATE_NO_MEMORY; 
  33.     } 
  34.  
  35.     intSave = LOS_IntLock(); 
  36. ⑷  if (LOS_ListEmpty(&g_freeQueueList)) { 
  37.         LOS_IntRestore(intSave); 
  38.         (VOID)LOS_MemFree(m_aucSysMem0, queue); 
  39.         return LOS_ERRNO_QUEUE_CB_UNAVAILABLE; 
  40.     } 
  41.  
  42. ⑸  unusedQueue = LOS_DL_LIST_FIRST(&(g_freeQueueList)); 
  43.     LOS_ListDelete(unusedQueue); 
  44.     queueCB = (GET_QUEUE_LIST(unusedQueue)); 
  45.     queueCB->queueLen = len; 
  46.     queueCB->queueSize = msgSize; 
  47.     queueCB->queue = queue; 
  48.     queueCB->queueState = OS_QUEUE_INUSED; 
  49.     queueCB->readWriteableCnt[OS_QUEUE_READ] = 0; 
  50.     queueCB->readWriteableCnt[OS_QUEUE_WRITE] = len; 
  51.     queueCB->queueHead = 0; 
  52.     queueCB->queueTail = 0; 
  53. ⑹  LOS_ListInit(&queueCB->readWriteList[OS_QUEUE_READ]); 
  54.     LOS_ListInit(&queueCB->readWriteList[OS_QUEUE_WRITE]); 
  55.     LOS_ListInit(&queueCB->memList); 
  56.     LOS_IntRestore(intSave); 
  57.  
  58. ⑺  *queueID = queueCB->queueID; 
  59.  
  60.     OsHookCall(LOS_HOOK_TYPE_QUEUE_CREATE, queueCB); 
  61.  
  62.     return LOS_OK; 

 3.2 隊列刪除

我們可以使用函數LOS_QueueDelete(UINT32 queueID)來刪除隊列,下面通過分析源碼看看如何刪除隊列的。

⑴處判斷隊列queueID是否超過LOSCFG_BASE_IPC_QUEUE_LIMIT,如果超過則返回錯誤碼。如果隊列編號沒有問題,獲取隊列控制塊LosQueueCB *queueCB。⑵處判斷要刪除的隊列處于未使用狀態,則跳轉到錯誤標簽QUEUE_END進行處理。⑶如果隊列的阻塞讀、阻塞寫任務列表不為空,或內存節點鏈表不為空,則不允許刪除,跳轉到錯誤標簽進行處理。⑷處檢驗隊列的可讀、可寫數量是否出錯。

⑸處使用指針UINT8 *queue保存隊列的內存空間,⑹處把.queue置空,把.queueState設置為未使用OS_QUEUE_UNUSED,并把隊列節點插入未使用隊列雙向鏈表g_freeQueueList。接下來會需要調用⑺處函數LOS_MemFree()釋放隊列內存空間。

  1. LITE_OS_SEC_TEXT_INIT UINT32 LOS_QueueDelete(UINT32 queueID) 
  2.     LosQueueCB *queueCB = NULL
  3.     UINT8 *queue = NULL
  4.     UINT32 intSave; 
  5.     UINT32 ret; 
  6.  
  7. ⑴  if (queueID >= LOSCFG_BASE_IPC_QUEUE_LIMIT) { 
  8.         return LOS_ERRNO_QUEUE_NOT_FOUND; 
  9.     } 
  10.  
  11.     intSave = LOS_IntLock(); 
  12.     queueCB = (LosQueueCB *)GET_QUEUE_HANDLE(queueID); 
  13. ⑵  if (queueCB->queueState == OS_QUEUE_UNUSED) { 
  14.         ret = LOS_ERRNO_QUEUE_NOT_CREATE; 
  15.         goto QUEUE_END; 
  16.     } 
  17.  
  18. ⑶  if (!LOS_ListEmpty(&queueCB->readWriteList[OS_QUEUE_READ])) { 
  19.         ret = LOS_ERRNO_QUEUE_IN_TSKUSE; 
  20.         goto QUEUE_END; 
  21.     } 
  22.  
  23.     if (!LOS_ListEmpty(&queueCB->readWriteList[OS_QUEUE_WRITE])) { 
  24.         ret = LOS_ERRNO_QUEUE_IN_TSKUSE; 
  25.         goto QUEUE_END; 
  26.     } 
  27.  
  28.     if (!LOS_ListEmpty(&queueCB->memList)) { 
  29.         ret = LOS_ERRNO_QUEUE_IN_TSKUSE; 
  30.         goto QUEUE_END; 
  31.     } 
  32.  
  33. ⑷  if ((queueCB->readWriteableCnt[OS_QUEUE_WRITE] + queueCB->readWriteableCnt[OS_QUEUE_READ]) != 
  34.         queueCB->queueLen) { 
  35.         ret = LOS_ERRNO_QUEUE_IN_TSKWRITE; 
  36.         goto QUEUE_END; 
  37.     } 
  38.  
  39. ⑸  queue = queueCB->queue; 
  40. ⑹  queueCB->queue = (UINT8 *)NULL
  41.     queueCB->queueState = OS_QUEUE_UNUSED; 
  42.     LOS_ListAdd(&g_freeQueueList, &queueCB->readWriteList[OS_QUEUE_WRITE]); 
  43.     LOS_IntRestore(intSave); 
  44.  
  45.     OsHookCall(LOS_HOOK_TYPE_QUEUE_DELETE, queueCB); 
  46.  
  47. ⑺  ret = LOS_MemFree(m_aucSysMem0, (VOID *)queue); 
  48.     return ret; 
  49.  
  50. QUEUE_END: 
  51.     LOS_IntRestore(intSave); 
  52.     return ret; 

 下面就來看看隊列的讀寫,有2點需要注意:

  • 隊首、隊尾的讀寫

只支持隊首讀取,不能隊尾讀取,否則就不算隊列了。除了正常的隊尾寫消息外,還提供插隊機制,支持從隊首寫入。

  • 隊列消息數據內容

往隊列中寫入的消息的類型有2種,即支持按地址寫入和按值寫入(帶拷貝)。按哪種類型寫入,就需要配對的按相應的類型去讀取。

隊列讀取接口的類別,歸納如下:

3.3 隊列讀取

我們知道有2個隊列讀取方法,按指針地址讀取的函數LOS_QueueRead()和按消息數值讀取的函數LOS_QueueReadCopy()。我們先看下函數LOS_QueueRead(),該函數的參數有4個,隊列編號queueID,存放讀取到的消息的緩沖區地址*bufferAddr,存放讀取到的消息的緩沖區大小bufferSize,讀隊列消息的等待超時時間timeOut。代碼如下,我們分析下代碼。

⑴處校驗傳入參數,隊列編號不能超出限制,傳入的指針不能為空,緩沖大小不能為0。如果timeout不為零,不能在中斷中讀取隊列。⑵處操作類型表示隊首讀取消息指針,然后調用函數OsQueueOperate()進一步操作隊列。

  1. LITE_OS_SEC_TEXT UINT32 LOS_QueueRead(UINT32 queueID, VOID *bufferAddr, UINT32 bufferSize, UINT32 timeOut) 
  2.     UINT32 ret; 
  3.     UINT32 operateType; 
  4.  
  5. ⑴  ret = OsQueueReadParameterCheck(queueID, bufferAddr, &bufferSize, timeOut); 
  6.     if (ret != LOS_OK) { 
  7.         return ret; 
  8.     } 
  9.  
  10. ⑵  operateType = OS_QUEUE_OPERATE_TYPE(OS_QUEUE_READ, OS_QUEUE_HEAD, OS_QUEUE_POINT); 
  11.  
  12.     OsHookCall(LOS_HOOK_TYPE_QUEUE_READ, (LosQueueCB *)GET_QUEUE_HANDLE(queueID)); 
  13.  
  14.     return OsQueueOperate(queueID, operateType, bufferAddr, &bufferSize, timeOut); 

 我們進一步分析下函數OsQueueOperate(),這是是比較通用的封裝,讀取,寫入都會調用這個函數,我們以讀取隊列為例分析這個函數。⑴處獲取隊列的操作類型,為讀取操作。⑵處先調用函數OsQueueOperateParamCheck()進行參數校驗,校驗隊列是使用中的隊列,并對讀寫消息大小進行校驗。⑶處如果可讀數量為0,無法讀取時,如果是零等待則返回錯誤碼。如果當前鎖任務調度,跳出函數執行。否則,執行⑷把當前任務放入隊列的讀取消息阻塞隊列,然后觸發任務調度,后續的代碼暫時不再執行。如果可讀的數量不為0,可以繼續讀取時,執行⑹處代碼把可讀數量減1,然后繼續執行⑺處代碼讀取隊列。

等讀取隊列阻塞超時,或者隊列可以讀取后,繼續執行⑸處的代碼。如果是發生超時,隊列還不能讀取,更改任務狀態,跳出函數執行。如果隊列可以讀取了,繼續執行⑺處代碼讀取隊列。⑻處在成功讀取隊列后,如果有任務阻塞在寫入隊列,則獲取阻塞鏈表中的第一個任務resumedTask,然后調用喚醒函數OsSchedTaskWake()把待恢復的任務放入就緒隊列,觸發一次任務調度。如果無阻塞任務,則把可寫入的數量加1。

  1. UINT32 OsQueueOperate(UINT32 queueID, UINT32 operateType, VOID *bufferAddr, UINT32 *bufferSize, UINT32 timeOut) 
  2.     LosQueueCB *queueCB = NULL
  3.     LosTaskCB *resumedTask = NULL
  4.     UINT32 ret; 
  5. ⑴  UINT32 readWrite = OS_QUEUE_READ_WRITE_GET(operateType); 
  6.     UINT32 readWriteTmp = !readWrite; 
  7.  
  8.     UINT32 intSave = LOS_IntLock(); 
  9.  
  10.     queueCB = (LosQueueCB *)GET_QUEUE_HANDLE(queueID); 
  11. ⑵  ret = OsQueueOperateParamCheck(queueCB, operateType, bufferSize); 
  12.     if (ret != LOS_OK) { 
  13.         goto QUEUE_END; 
  14.     } 
  15.  
  16. ⑶  if (queueCB->readWriteableCnt[readWrite] == 0) { 
  17.         if (timeOut == LOS_NO_WAIT) { 
  18.             ret = OS_QUEUE_IS_READ(operateType) ? LOS_ERRNO_QUEUE_ISEMPTY : LOS_ERRNO_QUEUE_ISFULL; 
  19.             goto QUEUE_END; 
  20.         } 
  21.  
  22.         if (g_losTaskLock) { 
  23.             ret = LOS_ERRNO_QUEUE_PEND_IN_LOCK; 
  24.             goto QUEUE_END; 
  25.         } 
  26.  
  27.         LosTaskCB *runTsk = (LosTaskCB *)g_losTask.runTask; 
  28. ⑷      OsSchedTaskWait(&queueCB->readWriteList[readWrite], timeOut); 
  29.         LOS_IntRestore(intSave); 
  30.         LOS_Schedule(); 
  31.  
  32.         intSave = LOS_IntLock(); 
  33. ⑸      if (runTsk->taskStatus & OS_TASK_STATUS_TIMEOUT) { 
  34.             runTsk->taskStatus &= ~OS_TASK_STATUS_TIMEOUT; 
  35.             ret = LOS_ERRNO_QUEUE_TIMEOUT; 
  36.             goto QUEUE_END; 
  37.         } 
  38.     } else { 
  39. ⑹       queueCB->readWriteableCnt[readWrite]--; 
  40.     } 
  41.  
  42. ⑺   OsQueueBufferOperate(queueCB, operateType, bufferAddr, bufferSize); 
  43.  
  44.  
  45. ⑻  if (!LOS_ListEmpty(&queueCB->readWriteList[readWriteTmp])) { 
  46.         resumedTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&queueCB->readWriteList[readWriteTmp])); 
  47.         OsSchedTaskWake(resumedTask); 
  48.         LOS_IntRestore(intSave); 
  49.         LOS_Schedule(); 
  50.         return LOS_OK; 
  51.     } else { 
  52. ⑼      queueCB->readWriteableCnt[readWriteTmp]++; 
  53.     } 
  54.  
  55. QUEUE_END: 
  56.     LOS_IntRestore(intSave); 
  57.     return ret; 

 我們再繼續看下函數OsQueueBufferOperate()是具體如何讀取隊列的。⑴處switch-case語句根據操作類型獲取操作位置。對于⑵頭部讀取的情況,先獲取讀取位置queuePosition。然后,如果當前頭節點位置.queueHead加1等于隊列消息長度,頭節點位置.queueHead設置為0,否則加1。對于⑶頭部寫入的情況,如果當前頭節點位置.queueHead等于0,頭節點位置.queueHead設置為隊列消息長度減1即queueCB->queueLen - 1,否則頭節點位置.queueHead減1即可。然后,獲取要寫入的位置queuePosition。對于⑷尾部寫入的情況,先獲取寫入位置queuePosition。然后,如果當前尾節點位置.queueTail加1等于隊列消息長度,尾節點位置.queueTail設置為0,否則加1。

⑸處基于獲取的隊列讀取位置獲取隊列消息節點queueNode。⑹處判斷操作類型如果是按指針讀寫消息,直接讀取消息節點的數據寫入指針對應的緩沖區*(UINT32 *)bufferAddr,或直接把指針對應的緩沖區*(UINT32 *)bufferAddr數據寫入消息節點即可。我們接著看如何按數數據讀寫消息,⑺處代碼用于讀取數據消息。每個消息節點的后4個字節保存的是消息的長度,首先獲取消息的長度msgDataSize,然后把消息內容讀取到bufferAddr。再看看⑻處如何寫入隊列消息,首先把消息內容寫入到queueNode,然后再把消息長度的內容寫入到queueNode + queueCB->queueSize - sizeof(UINT32),就是每個消息節點的后4字節。

  1. static INLINE VOID OsQueueBufferOperate(LosQueueCB *queueCB, UINT32 operateType, 
  2.                                                                 VOID *bufferAddr, UINT32 *bufferSize) 
  3.     UINT8 *queueNode = NULL
  4.     UINT32 msgDataSize; 
  5.     UINT16 queuePosion; 
  6.     errno_t rc; 
  7.  
  8.     /* get the queue position */ 
  9. ⑴  switch (OS_QUEUE_OPERATE_GET(operateType)) { 
  10.         case OS_QUEUE_READ_HEAD: 
  11. ⑵          queuePosion = queueCB->queueHead; 
  12.             ((queueCB->queueHead + 1) == queueCB->queueLen) ? (queueCB->queueHead = 0) : (queueCB->queueHead++); 
  13.             break; 
  14.  
  15.         case OS_QUEUE_WRITE_HEAD: 
  16. ⑶          (queueCB->queueHead == 0) ? (queueCB->queueHead = (queueCB->queueLen - 1)) : (--queueCB->queueHead); 
  17.             queuePosion = queueCB->queueHead; 
  18.             break; 
  19.  
  20.         case OS_QUEUE_WRITE_TAIL: 
  21. ⑷          queuePosion = queueCB->queueTail; 
  22.             ((queueCB->queueTail + 1) == queueCB->queueLen) ? (queueCB->queueTail = 0) : (queueCB->queueTail++); 
  23.             break; 
  24.  
  25.         default
  26.             PRINT_ERR("invalid queue operate type!\n"); 
  27.             return
  28.     } 
  29.  
  30. ⑸  queueNode = &(queueCB->queue[(queuePosion * (queueCB->queueSize))]); 
  31.  
  32. ⑹  if (OS_QUEUE_IS_POINT(operateType)) { 
  33.       if (OS_QUEUE_IS_READ(operateType)) { 
  34.             *(UINT32 *)bufferAddr = *(UINT32 *)(VOID *)queueNode; 
  35.         } else { 
  36.             *(UINT32 *)(VOID *)queueNode = *(UINT32 *)bufferAddr;  // change to pp when calling OsQueueOperate 
  37.         } 
  38.     } else { 
  39. ⑺      if (OS_QUEUE_IS_READ(operateType)) { 
  40.             msgDataSize = *((UINT32 *)(UINTPTR)((queueNode + queueCB->queueSize) - sizeof(UINT32))); 
  41.             rc = memcpy_s((VOID *)bufferAddr, *bufferSize, (VOID *)queueNode, msgDataSize); 
  42.             if (rc != EOK) { 
  43.                 PRINT_ERR("%s[%d] memcpy failed, error type = %u\n", __FUNCTION__, __LINE__, rc); 
  44.                 return
  45.             } 
  46.  
  47.             *bufferSize = msgDataSize; 
  48.         } else { 
  49. ⑻          *((UINT32 *)(UINTPTR)((queueNode + queueCB->queueSize) - sizeof(UINT32))) = *bufferSize; 
  50.             rc = memcpy_s((VOID *)queueNode, queueCB->queueSize, (VOID *)bufferAddr, *bufferSize); 
  51.             if (rc != EOK) { 
  52.                 PRINT_ERR("%s[%d] memcpy failed, error type = %u\n", __FUNCTION__, __LINE__, rc); 
  53.                 return
  54.             } 
  55.         } 
  56.     } 

 3.4 隊列寫入

我們知道,有4個隊列寫入方法,2個隊尾寫入,2個隊首寫入,分別包含按指針地址寫入消息和按數值寫入消息。LOS_QueueWrite()會調用LOS_QueueWriteCopy(),LOS_QueueWriteHead()會調用LOS_QueueWriteHeadCopy(),然后指定不同的操作類型后,會進一步調用前文已經分析過的函數OsQueueOperate()。

小結

本文帶領大家一起剖析了鴻蒙輕內核的隊列模塊的源代碼,包含隊列的結構體、隊列池初始化、隊列創建刪除、讀寫消息等。

想了解更多內容,請訪問:

51CTO和華為官方合作共建的鴻蒙技術社區

https://harmonyos.51cto.com

 

責任編輯:jianghua 來源: 鴻蒙社區
相關推薦

2021-09-22 14:36:32

鴻蒙HarmonyOS應用

2022-01-12 10:50:23

鴻蒙HarmonyOS應用

2022-01-10 15:31:44

鴻蒙HarmonyOS應用

2021-06-04 09:57:49

鴻蒙HarmonyOS應用

2021-05-12 09:45:20

鴻蒙HarmonyOS應用

2021-05-17 09:28:59

鴻蒙HarmonyOS應用

2021-05-08 15:14:50

鴻蒙HarmonyOS應用

2021-10-20 16:08:57

鴻蒙HarmonyOS應用

2021-05-25 09:28:34

鴻蒙HarmonyOS應用

2021-05-31 20:30:55

鴻蒙HarmonyOS應用

2022-03-11 20:23:14

鴻蒙源碼分析進程管理

2022-03-03 18:28:28

Harmony進程任務管理模塊

2022-04-13 11:02:12

鴻蒙事件模塊事件Event

2021-07-06 09:45:03

鴻蒙HarmonyOS應用

2021-05-11 09:54:55

鴻蒙HarmonyOS應用

2021-05-27 09:43:56

鴻蒙HarmonyOS應用

2021-06-09 09:48:01

鴻蒙HarmonyOS應用

2021-05-21 09:25:11

鴻蒙HarmonyOS應用

2022-01-14 08:39:47

鴻蒙HarmonyOS應用

2021-05-10 15:05:56

鴻蒙HarmonyOS應用
點贊
收藏

51CTO技術棧公眾號

最新天堂在线视频| 亚洲综合第一| 五月天中文字幕| 亚洲精品成人影院| 精品美女一区二区| 久草精品在线播放| 草逼视频免费看| 亚洲欧美日韩专区| 久久色在线播放| 18禁裸乳无遮挡啪啪无码免费| 国模雨婷捆绑高清在线| 久久综合狠狠综合| 亚洲一区二区中文| 在线观看 亚洲| 午夜精品久久| 精品欧美久久久| 日本 片 成人 在线| 精品精品导航| 亚洲欧洲日产国码二区| 久久免费视频1| 国产三级第一页| 日韩精品专区| 一区二区三区产品免费精品久久75| 成人黄色在线观看| 亚洲国产成人无码av在线| 欧美1区3d| 色偷偷88888欧美精品久久久| 国内自拍视频网| 国产传媒在线| 亚洲一区二区三区三| 国产九色91| 国产三级在线观看视频| 日本三级亚洲精品| 欧美性受xxx| 日韩av电影网址| 欧美日韩亚洲国产精品| 久久亚洲精品视频| 国产精品久久免费观看| 一本色道久久综合亚洲精品酒店 | 污污的视频在线免费观看| 五月激激激综合网色播| 欧美成人精品1314www| a在线观看免费视频| 久久野战av| 亚洲精品中文字幕在线观看| 亚洲一区二区三区加勒比| 可以在线观看的av网站| 久久综合九色综合欧美就去吻| 国产色综合天天综合网| 在线免费观看视频网站| 日本欧美一区二区三区乱码| 日产日韩在线亚洲欧美 | 国产色一区二区| 91日本在线观看| 国产强被迫伦姧在线观看无码| 一区二区三区国产盗摄| xxx一区二区| 三级黄色录像视频| 欧美freesextv| xvideos国产精品| 国产又黄又爽又无遮挡| 欧美国产三区| 国模视频一区二区| 亚洲色图27p| 51精产品一区一区三区| 九九九久久久久久| 精品一区二区6| 欧美h版在线| 久久五月天综合| 永久免费av无码网站性色av| 日韩综合精品| 久久亚洲综合国产精品99麻豆精品福利| 亚洲 欧美 日韩在线| 久久久久97| 欧美大片日本大片免费观看| 久久精品无码专区| 欧美三级电影在线| 国产一区二区欧美日韩| 中文成人无字幕乱码精品区| 亚洲制服欧美另类| 中文字幕日韩在线观看| 免费成年人视频在线观看| 日韩aaaa| 欧美日韩国产成人在线观看| www成人在线| 日本不卡高清视频| 国产91在线播放九色快色| 成人免费一区二区三区| 国产精品综合视频| 久久亚洲免费| 黄色在线免费网站| 五月综合激情网| 日韩精品视频一二三| 亚洲精品aⅴ| 亚洲视屏在线播放| 波多野结衣亚洲色图| 亚洲一区日韩在线| 91久久在线观看| 五月激情六月婷婷| 日韩一区中文字幕| 狠狠爱免费视频| 黄色网页在线观看| 国产欧美日产一区| 日韩精品不卡| 欧美理论片在线播放| 色婷婷亚洲精品| 台湾佬美性中文| 欧美日韩国产一区二区三区不卡 | 在线观看视频91| 污免费在线观看| 一区二区亚洲视频| 中文字幕成人精品久久不卡| 国产无套内射又大又猛又粗又爽 | 中文字幕精品一区二区三区精品| 欧美另类高清视频在线| gogogogo高清视频在线| 一区二区三区日韩欧美| 日韩亚洲一区在线播放| 黄色成人在线网| 欧美日韩大陆一区二区| 偷拍夫妻性生活| 一区二区三区四区五区精品视频 | 成人在线视频www| 亚洲男人的天堂在线| 中文天堂资源在线| 麻豆91精品| 国产一区二区高清视频| av免费在线观| 欧美精品久久久久久久久老牛影院| 中文字幕日韩综合| 欧美三级情趣内衣| 5566日本婷婷色中文字幕97| 无码一区二区三区在线观看| 国产欧美亚洲一区| 99视频在线免费观看| 免费a在线看| 欧美日韩一区二区欧美激情 | 午夜爽爽爽男女免费观看| 丝瓜av网站精品一区二区 | 亚洲视频在线免费观看| 在线观看中文字幕视频| 国产传媒日韩欧美成人| 伊人久久大香线蕉成人综合网| 狂野欧美性猛交xxxxx视频| 制服丝袜av成人在线看| 娇小11一12╳yⅹ╳毛片| 天堂久久一区二区三区| 99国产高清| 国产黄色在线| 欧美中文字幕亚洲一区二区va在线 | 蜜臀av一区二区三区有限公司| 久久视频国产| 国产精品日韩欧美| 日本在线www| 91精品在线免费| 在线看的片片片免费| 国产精品影视在线观看| 中文字幕日韩精品无码内射| 亚洲3区在线| 欧美激情精品在线| 无码国产伦一区二区三区视频 | 九色91在线视频| 天堂√8在线中文| 亚洲欧美一区二区三区久久 | 色狠狠色狠狠综合| 成人黄色免费网址| 欧美高清在线| 91在线观看免费高清完整版在线观看| 每日更新在线观看av| 在线亚洲一区二区| www成人啪啪18软件| 精品一区二区免费视频| 特级西西444| 成人午夜网址| 日本午夜精品理论片a级appf发布| 国产sm主人调教女m视频| 国产欧美一区二区精品性色超碰 | 可以看av的网站久久看| 高清不卡一区二区三区| 国产色播av在线| 亚洲天堂第一页| 国产毛片久久久久| 亚洲电影在线免费观看| 久久亚洲无码视频| 国产乱子伦一区二区三区国色天香| 日韩不卡av| 国产精品久久久久久av公交车| 一区二区三区回区在观看免费视频| 伊人久久综合视频| 中文字幕av一区 二区| 国产精品19p| 久久精品主播| 黑人巨茎大战欧美白妇| 少妇精品导航| 91精品视频播放| 亚洲综合电影| 九九热最新视频//这里只有精品| 国产精品无码AV| 欧美日韩激情美女| 91香蕉视频在线播放| 激情五月婷婷综合网| 欧美精品一区免费| 91高清一区| 人禽交欧美网站免费| 欧美精品三级在线| 国产成人在线一区| 黄网在线免费看| xvideos成人免费中文版| 外国精品视频在线观看 | 99精品在线观看| 精品一区二区三区视频日产| 999久久久国产999久久久| 欧美亚洲视频在线观看| 色老头在线观看| 亚洲精品国产美女| 一级黄色av片| 五月天精品一区二区三区| 动漫性做爰视频| 国产精品视频一区二区三区不卡| 色噜噜狠狠一区二区三区狼国成人 | 亚洲国产欧美在线成人app| 亚洲午夜激情视频| 91高清视频在线| 99精品在线播放| 午夜精品久久久久久久久久久| 久久久亚洲av波多野结衣| 豆国产96在线|亚洲| 日韩日韩日韩日韩日韩| **女人18毛片一区二区| 在线国产99| 欧美老女人另类| 日韩女优中文字幕| 国产精品三级| 欧美在线播放一区二区| 欧美日韩一本| 麻豆精品传媒视频| 欧美一区二区三区久久| 精品在线观看一区二区| 果冻天美麻豆一区二区国产| 国产超碰91| 爱爱精品视频| 国产精品一区二区三区不卡| 深夜福利一区| 国产精品久久久久久久久婷婷 | 国产69久久| 亚洲片av在线| 男人天堂网在线视频| 欧美一区二区黄| 精品黑人一区二区三区在线观看 | 中文字幕+乱码+中文字幕一区| 一区二区在线免费观看视频| 日韩高清不卡一区二区| 精品少妇无遮挡毛片| 日本欧美韩国一区三区| 欧美一级视频在线播放| 亚洲经典在线| 国产成人在线免费看| 免费日韩av片| 久无码久无码av无码| 亚洲黄页一区| 狠狠爱免费视频| 美女性感视频久久| 热久久久久久久久| 国产凹凸在线观看一区二区| 9.1在线观看免费| 激情亚洲综合在线| 国内自拍偷拍视频| 久久久久久亚洲综合影院红桃| 国产高潮失禁喷水爽到抽搐| 成人黄色在线看| 免费污网站在线观看| 中文字幕在线视频一区| 亚洲AV无码成人精品区明星换面| 暴力调教一区二区三区| 污免费在线观看| 97久久超碰国产精品电影| a级片在线观看| 亚洲人一二三区| 97免费在线观看视频| 欧美亚洲动漫制服丝袜| 99久久精品国产一区色| 欧美色网站导航| 精品人妻aV中文字幕乱码色欲| 欧美猛男gaygay网站| 亚洲AV午夜精品| 亚洲色图狂野欧美| 高h视频在线观看| 欧美亚洲成人网| a一区二区三区亚洲| 国产在线资源一区| 久久一本综合| 欧美成人三级在线视频| 六月丁香婷婷久久| 91视频在线免费| 国产精品美女久久久久久久久| 超薄肉色丝袜一二三| 亚洲综合丝袜美腿| 欧美性猛交xxxx乱大交hd| 日韩欧美国产电影| 久久久久国产精品嫩草影院| 久久国产精品久久久| 亚洲羞羞网站| 国产精品成熟老女人| 亚洲91网站| 精品国产一区二区三区日日嗨 | 外国电影一区二区| 国产精品美女久久| 国产精品中文字幕制服诱惑| 亚洲精品一区国产精品| 一区二区三区高清视频在线观看| 国产日韩成人内射视频| 国产成人在线网站| 亚洲欧美卡通动漫| 日韩欧美精品免费在线| 亚洲AV无码精品色毛片浪潮| 正在播放欧美视频| 深夜在线视频| 国产亚洲欧美一区二区| 欧美另类女人| 在线视频观看91| 亚洲国产成人午夜在线一区| 日韩av大片在线观看| 日本高清不卡视频| 午夜视频在线播放| 欧美激情手机在线视频 | 少妇av一区二区| 欧美高跟鞋交xxxxhd| 豆花视频一区| 一级做a爰片久久| 欧美aaa在线| 我不卡一区二区| 在线一区二区三区| 久草在线青青草| 国产成人精品一区二区在线| 欧美人妖视频| 欧美亚洲另类色图| 91玉足脚交白嫩脚丫在线播放| jizz日本在线播放| 欧美最新大片在线看| www日本在线| 欧美人与性动交a欧美精品| 97久久精品一区二区三区的观看方式| 国产亚洲一区在线播放| 在线看片一区| 精品视频站长推荐| 精品久久久久久中文字幕| 三级做a全过程在线观看| 91tv亚洲精品香蕉国产一区7ujn| 久久免费资源| 伊人久久大香线蕉综合75| 国内精品国产三级国产a久久| 五月天综合视频| 日本二三区不卡| 在线免费黄色| 91亚洲精品一区| 欧美日韩亚洲一区三区| 中文字幕三级电影| 一本到一区二区三区| 亚洲精品97久久中文字幕| 中文字幕av一区二区| 松下纱荣子在线观看| 日韩av不卡播放| 久久99久久精品| 欧美成人三级视频| 亚洲国产精品久久精品怡红院| www在线免费观看视频| 99爱精品视频| 久久精品午夜| 国产精品国产三级国产传播| 欧美xxxxxxxx| 国模套图日韩精品一区二区| 亚洲视频电影| 成人丝袜视频网| 波多野结衣视频网址| 久久久精品视频成人| 巨人精品**| 男人添女人下面免费视频| 一区二区三区四区高清精品免费观看| 91高潮大合集爽到抽搐| 欧美肥婆姓交大片| 最新国产一区| 国产乱码一区二区三区四区| 亚洲成人午夜电影| 亚洲av无码一区二区三区dv | 97伦理在线四区| 外国成人免费视频| 亚洲视频在线播放免费| 在线免费不卡视频| 污污的网站在线免费观看| 久久一区二区三区av| 激情深爱一区二区| 亚洲天堂一区在线观看| 久久亚洲电影天堂| 欧美女王vk| 无码人妻一区二区三区一| 日本韩国欧美一区二区三区| 色呦呦在线视频| 亚洲一区二区三区四区中文| 久久99九九99精品| 日韩精品手机在线|