鴻蒙內核源碼分析(雙向鏈表篇) | 誰是內核最重要結構體 ?

鴻蒙內核源碼注釋中文版 < Gitee倉 | CSDN倉 | Github倉 | Coding倉 >精讀內核源碼,中文註解分析,深挖地基工程,構建底層網圖,四大碼倉每日同步更新

鴻蒙源碼分析系列篇 < CSDN | OSCHINA | WeHarmony | 公眾號 >問答式導讀,生活式比喻,表格化說明,圖形化展示,主流站點每日同步更新

 
誰是鴻蒙內核最重要的結構體?
答案一定是: LOS_DL_LIST(雙向鏈表),它長這樣.

typedef struct LOS_DL_LIST {//雙向鏈表,內核最重要結構體
    struct LOS_DL_LIST *pstPrev; /**< Current node's pointer to the previous node *///前驅節點(左手)
    struct LOS_DL_LIST *pstNext; /**< Current node's pointer to the next node *///後繼節點(右手)
} LOS_DL_LIST;

 

  
結構體夠簡單了吧,只有前後兩個指向自己的指針,但恰恰是因為太簡單,所以才太不簡單. 就像氫原子一樣,宇宙中無處不在,佔比最高,原因是因為它最簡單,最穩定!

內核的各自模組都能看到雙向鏈表的身影,下圖是各處初始化雙向鏈表的操作,因為太多了,只截取了部分:

 

很多人問圖怎麼來的, source insight 4.0 是閱讀大型C/C++工程的必備工具,要用4.0否則中文有亂碼.

可以豪不誇張的說理解LOS_DL_LIST及相關函數是讀懂鴻蒙內核的關鍵。前後指針(注者後續將比喻成一對左右觸手)靈活的指揮著系統精準的運行,越是深入分析內核源碼,越能感受到內核開發者對LOS_DL_LIST非凡的駕馭能力,筆者彷彿看到了無數雙手前後相連,拉起了一個個雙向循環鏈表,把指針的高效能運用到了極致,這也許就是編程的藝術吧!這麼重要的結構體還是需詳細講解一下.

基本概念
雙向鏈表是指含有往前和往後兩個方向的鏈表,即每個結點中除存放下一個節點指針外,還增加一個指向其前一個節點的指針。其頭指針head是唯一確定的。從雙向鏈表中的任意一個結點開始,都可以很方便地訪問它的前驅結點和後繼結點,這種數據結構形式使得雙向鏈表在查找時更加方便,特別是大量數據的遍歷。由於雙向鏈表具有對稱性,能方便地完成各種插入、刪除等操作,但需要注意前後方向的操作。

功能介面
鴻蒙系統中的雙向鏈表模組為用戶提供下面幾個介面。

請結合下面的程式碼和圖去理解雙向鏈表,不管花多少時間,一定要理解它的插入/刪除動作, 否則後續內容將無從談起.

//將指定節點初始化為雙向鏈表節點
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListInit(LOS_DL_LIST *list)
{
    list->pstNext = list;
    list->pstPrev = list;
}

//將指定節點掛到雙向鏈表頭部
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListAdd(LOS_DL_LIST *list, LOS_DL_LIST *node)
{
    node->pstNext = list->pstNext;
    node->pstPrev = list;
    list->pstNext->pstPrev = node;
    list->pstNext = node;
}
//將指定節點從鏈表中刪除,自己把自己摘掉
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListDelete(LOS_DL_LIST *node)
{
    node->pstNext->pstPrev = node->pstPrev;
    node->pstPrev->pstNext = node->pstNext;
    node->pstNext = NULL;
    node->pstPrev = NULL;
}

 

  具體用法
舉例 ProcessCB(進程式控制制塊)是描述一個進程的所有資訊,其中用到了 8個雙向鏈表,這簡直比章魚還牛逼,章魚也才四雙觸手,但進程有8雙(16隻)觸手.

typedef struct ProcessCB {
    LOS_DL_LIST          pendList;                     /**< Block list to which the process belongs */ //進程所屬的阻塞列表,如果因拿鎖失敗,就由此節點掛到等鎖鏈表上
    LOS_DL_LIST          childrenList;                 /**< my children process list */ //孩子進程都掛到這裡,形成雙循環鏈表
    LOS_DL_LIST          exitChildList;                /**< my exit children process list */ //那些要退出孩子進程掛到這裡,白髮人送黑髮人。
    LOS_DL_LIST          siblingList;                  /**< linkage in my parent's children list */ //兄弟進程鏈表, 56個民族是一家,來自同一個父進程.
    ProcessGroup         *group;                       /**< Process group to which a process belongs */ //所屬進程組
    LOS_DL_LIST          subordinateGroupList;         /**< linkage in my group list */ //進程是組長時,有哪些組員進程
    UINT32               threadGroupID;                /**< Which thread group , is the main thread ID of the process */ //哪個執行緒組是進程的主執行緒ID
    UINT32               threadScheduleMap;            /**< The scheduling bitmap table for the thread group of the
                                                            process */ //進程的各執行緒調度點陣圖
    LOS_DL_LIST          threadSiblingList;            /**< List of threads under this process *///進程的執行緒(任務)列表
    LOS_DL_LIST          threadPriQueueList[OS_PRIORITY_QUEUE_NUM]; /**< The process's thread group schedules the
                                                                         priority hash table */ //進程的執行緒組調度優先順序哈希表
    volatile UINT32      threadNumber; /**< Number of threads alive under this process */ //此進程下的活動執行緒數
    UINT32               threadCount;  /**< Total number of threads created under this process */ //在此進程下創建的執行緒總數
    LOS_DL_LIST          waitList;     /**< The process holds the waitLits to support wait/waitpid *///進程持有等待鏈表以支援wait/waitpid
} LosProcessCB;

 

  
看個簡單點的 pendList表示這個進程中所有被阻塞的任務(task)都會掛到這個鏈表上管理. 任務阻塞的原因很多,可能是申請互斥鎖失敗,可能等待事件讀消息隊列,還可能開了一個定時任務等等.

再來看一個複雜點的 threadPriQueueList,這又是幹嘛的?從名字可以看出來是執行緒的隊列鏈表,在鴻蒙內核執行緒就是任務(task),任務分等了32個優先順序,同級的任務放在同一個雙向鏈表中, 32級就是32個雙向鏈表,所以是個鏈表數組,每條鏈表中存放的是已就緒等待被調度的任務.

雙向鏈表是內核最重要的結構體,精讀內核的路上它會反覆的映入你的眼帘,理解它是理解記憶體運作的關鍵所在!

作者:weharmony

想了解更多內容,請訪問: 51CTO和華為官方戰略合作共建的鴻蒙技術社區//harmonyos.51cto.com/

Tags: