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

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

鴻蒙源碼分析系列篇 < 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是惟一肯定的。從雙向鏈表中的任意一個結點開始,均可以很方便地訪問它的前驅結點和後繼結點,這種數據結構形式使得雙向鏈表在查找時更加方便,特別是大量數據的遍歷。因爲雙向鏈表具備對稱性,能方便地完成各類插入、刪除等操做,但須要注意先後方向的操做。this

功能接口
鴻蒙系統中的雙向鏈表模塊爲用戶提供下面幾個接口。spa

請結合下面的代碼和圖去理解雙向鏈表,無論花多少時間,必定要理解它的插入/刪除動做, 不然後續內容將無從談起.線程

//將指定節點初始化爲雙向鏈表節點
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和華爲官方戰略合做共建的鴻蒙技術社區https://harmonyos.51cto.com/

相關文章
相關標籤/搜索