鴻蒙核心原始碼中文註解 >> 精讀核心原始碼,中文註解分析,深挖地基工程,大腦永久記憶,四大原始碼倉每日同步更新
官方基本概念從系統的角度看,程序是資源管理單元。程序可以使用或等待CPU、使用記憶體空間等系統資源,並獨立於其它程序執行。
鴻蒙核心的程序模組可以給使用者提供多個程序,實現了程序之間的切換和通訊,幫助使用者管理業務程式流程。這樣使用者可以將更多的精力投入到業務功能的實現中。
鴻蒙核心中的程序採用搶佔式排程機制,支援時間片輪轉排程方式和FIFO排程機制。
鴻蒙核心的程序一共有32個優先順序(0-31),使用者程序可配置的優先順序有22個(10-31),最高優先順序為10,最低優先順序為31。
高優先順序的程序可搶佔低優先順序程序,低優先順序程序必須在高優先順序程序阻塞或結束後才能得到排程。
每一個使用者態程序均擁有自己獨立的程序空間,相互之間不可見,實現程序間隔離。
官方概念解讀官方文件最重要的一句話是程序是資源管理單元,注意是管理資源的, 資源是什麼? 記憶體,任務,檔案,訊號量等等都是資源.故事篇中對程序做了一個形象的比喻(導演),負責節目(任務)的演出,負責協調節目執行時所需的各種資源.讓節目能高效順利的完成.
ProcessCB真身typedef struct ProcessCB { CHAR processName[OS_PCB_NAME_LEN]; /**< Process name */ //程序名稱 UINT32 processID; /**< process ID = leader thread ID */ //程序ID,由程序池分配,範圍[0,64] UINT16 processStatus; /**< [15:4] process Status; [3:0] The number of threads currently running in the process *///這裡設計很巧妙.用一個16表示了兩層邏輯 數量和狀態,點贊! UINT16 priority; /**< process priority */ //程序優先順序 UINT16 policy; /**< process policy */ //程序的排程方式,預設搶佔式 UINT16 timeSlice; /**< Remaining time slice *///程序時間片,預設2個tick UINT16 consoleID; /**< The console id of task belongs *///任務的控制檯id歸屬 UINT16 processMode; /**< Kernel Mode:0; User Mode:1; */ //模式指定為核心還是使用者程序 UINT32 parentProcessID; /**< Parent process ID */ //父程序ID UINT32 exitCode; /**< process exit status */ //程序退出狀態碼 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#if (LOSCFG_KERNEL_SMP == YES) UINT32 timerCpu; /**< CPU core number of this task is delayed or pended *///統計各執行緒被延期或阻塞的時間#endif UINTPTR sigHandler; /**< signal handler */ //訊號處理函式,處理如 SIGSYS 等訊號 sigset_t sigShare; /**< signal share bit */ //訊號共享位#if (LOSCFG_KERNEL_LITEIPC == YES) ProcIpcInfo ipcInfo; /**< memory pool for lite ipc */ //用於程序間通訊的虛擬裝置檔案系統,裝置裝載點為 /dev/lite_ipc#endif LosVmSpace *vmSpace; /**< VMM space for processes */ //虛擬空間,描述程序虛擬記憶體的資料結構,linux稱為記憶體描述符#ifdef LOSCFG_FS_VFS struct files_struct *files; /**< Files held by the process */ //程序所持有的所有檔案,注者稱之為程序的檔案管理器#endif //每個程序都有屬於自己的檔案管理器,記錄對檔案的操作. 注意:一個檔案可以被多個程序操作 timer_t timerID; /**< iTimer */#ifdef LOSCFG_SECURITY_CAPABILITY //安全能力 User *user; //程序的擁有者 UINT32 capability; //安全能力範圍 對應 CAP_SETGID#endif#ifdef LOSCFG_SECURITY_VID TimerIdMap timerIdMap;#endif#ifdef LOSCFG_DRIVERS_TZDRIVER struct file *execFile; /**< Exec bin of the process */#endif mode_t umask;} LosProcessCB;
結構體還是比較複雜,雖一一都做了註解,但還是不夠清晰,沒有模組化.這裡把它分解成以下六大塊逐一分析:
中的執行緒篇中有詳細的介紹,可自行翻看. 任務是作為一種資源被程序管理的,程序為任務提供記憶體支援,提供檔案支援,提供裝置支援.
程序怎麼管理執行緒的,程序怎麼同步執行緒的狀態?
1.程序載入時會找到main函式建立第一個執行緒,一般為主執行緒,main函式就是入口函式,一切從哪裡開始.
2.執行過程中根據程式碼(如遇到 new thread )建立新的執行緒,其本質和main函式建立的執行緒沒有區別,只是入口函式變成了run()[以java舉例],統一參與排程.
3.執行緒和執行緒的關係可以是獨立(detached)的,也可以是聯結(join)的.聯結指的是一個執行緒可以操作另一個執行緒(包括回收資源,被對方幹掉).
4.程序的主執行緒或所有執行緒執行結束後,程序轉為殭屍態,一般只能由所有執行緒結束後,程序才能自然消亡.
5.程序建立後進入就緒態,發生程序切換時,就緒列表中最高優先順序的程序被執行,從而進入執行態。若此時該程序中已無其它執行緒處於就緒態,則該程序從就緒列表刪除,只處於執行態;若此時該程序中還有其它執行緒處於就緒態,則該程序依舊在就緒佇列,此時程序的就緒態和執行態共存。這裡要注意的是程序可以允許多種狀態並存! 狀態並存很自然地會想到點陣圖管理,系列篇中有對點陣圖詳細的介紹.
6.程序內所有的執行緒均處於阻塞態時,程序在最後一個執行緒轉為阻塞態時,同步進入阻塞態,然後發生程序切換。
7.阻塞程序內的任意執行緒恢復就緒態時,程序被加入到就緒佇列,同步轉為就緒態,若此時發生程序切換,則程序狀態由就緒態轉為執行態
9.程序由執行態轉為就緒態的情況有以下兩種:
有更高優先順序的程序建立或者恢復後,會發生程序排程,此刻就緒列表中最高優先順序程序變為執行態,那麼原先執行的程序由執行態變為就緒態。
若程序的排程策略為SCHED_RR(搶佔式),且存在同一優先順序的另一個程序處於就緒態,則該程序的時間片消耗光之後,該程序由執行態轉為就緒態,另一個同優先順序的程序由就緒態轉為執行態。
第二大塊:和其他程序的關係 CHAR processName[OS_PCB_NAME_LEN]; /**< Process name */ //程序名稱 UINT32 processID; /**< process ID = leader thread ID */ //程序ID,由程序池分配,範圍[0,64] UINT16 processStatus; /**< [15:4] process Status; [3:0] The number of threads currently running in the process *///這裡設計很巧妙.用一個16表示了兩層邏輯 數量和狀態,點贊! UINT16 priority; /**< process priority */ //程序優先順序 UINT16 policy; /**< process policy */ //程序的排程方式,預設搶佔式 UINT16 timeSlice; /**< Remaining time slice *///程序時間片,預設2個tick UINT16 consoleID; /**< The console id of task belongs *///任務的控制檯id歸屬 UINT16 processMode; /**< Kernel Mode:0; User Mode:1; */ //模式指定為核心還是使用者程序 UINT32 parentProcessID; /**< Parent process ID */ //父程序ID UINT32 exitCode; /**< process exit status */ //程序退出狀態碼 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個民族是一家,來自同一個父程序. #if (LOSCFG_KERNEL_LITEIPC == YES) ProcIpcInfo ipcInfo; /**< memory pool for lite ipc */ //用於程序間通訊的虛擬裝置檔案系統,裝置裝載點為 /dev/lite_ipc #endif
程序是家族式管理的,核心態程序和使用者態程序分別有自己的根祖先,祖先程序在核心初始化時就建立好了,分別是1號(使用者程序祖先)和2號(核心程序祖先)程序.程序剛生下來就確定了自己的基因,基因決定了你的許可權不同, 父親是誰,兄弟姐妹都有誰都已經安排好了,跟人一樣,沒法選擇出生. 但程序可以有自己的子子孫孫, 從你這一脈繁衍下來的,這很像人類的傳承方式.最終會形成樹狀結構,每個程序都能找到自己的位置.程序的管理遵循以下幾點原則:
1.程序退出時會主動釋放持有的程序資源,但持有的程序pid資源需要父程序透過wait/waitpid或父程序退出時回收.
2.一個子程序的消亡要通知父程序,以便父程序在族譜上抹掉它的痕跡,一些異常情況下的壞孩子程序消亡沒有告知父程序的,系統也會有定時任務能檢測到而回收其資源.
3.程序建立後,只能操作自己程序空間的資源,無法操作其它程序的資源(共享資源除外).
4.程序間有多種通訊方式,事件,訊號,訊息佇列,管道等等, liteipc是程序間基於檔案的一種通訊方式,它的特點是傳遞的資訊量可以很大.
5.高優先順序的程序可搶佔低優先順序程序,低優先順序程序必須在高優先順序程序阻塞或結束後才能得到排程。
第三大塊:程序的五種狀態初始化(Init):該程序正在被建立。
就緒(Ready):該程序在就緒列表中,等待CPU排程。
執行(Running):該程序正在執行。
阻塞(Pend):該程序被阻塞掛起。本程序內所有的執行緒均被阻塞時,程序被阻塞掛起。
殭屍態(Zombies):該程序執行結束,等待父程序回收其控制塊資源。
檢視記憶體篇.詳細介紹了虛擬記憶體,物理記憶體,線性地址,對映關係,共享記憶體,分配回收,頁面置換的概念和實現.
第五大塊:和檔案的關係#ifdef LOSCFG_FS_VFS struct files_struct *files; /**< Files held by the process */ //程序所持有的所有檔案,注者稱之為程序的檔案管理器#endif //每個程序都有屬於自己的檔案管理器,記錄對檔案的操作. 注意:一個檔案可以被多個程序操作
程序與檔案系統有關的就只有files_struct,可理解為程序的檔案管理器,檔案也是很複雜的一大塊, 後續有系列篇來講解檔案系統的實現. 理解檔案系統的主脈絡是:
1.一個真實的物理檔案(inode),可以同時被多個程序開啟,並有程序獨立的檔案描述符, 程序檔案描述符(ProcessFD)後邊對映的是系統檔案描述符(SystemFD).
2.系統檔案描述符(0-stdin,1-stdout,2-stderr)預設被核心佔用,任何程序的檔案描述符前三個都是(stdin,stdout,stderr),預設已經開啟,可以直接往裡面讀寫資料.
3.檔案對映跟記憶體對映一樣,每個程序都需要單獨對同一個檔案進行對映,page_mapping記錄了對映關係,而頁快取記憶體(page cache)提供了檔案實際記憶體存放位置.
4.記憶體<->檔案的置換以頁為單位(4K),程序並不能對硬碟檔案直接操作,必須透過頁快取記憶體(page cache)完成.其中會涉及到一些經典的概念比如COW(寫時複製)技術.後續會詳細說明.
第六大塊:輔助工具#if (LOSCFG_KERNEL_SMP == YES) UINT32 timerCpu; /**< CPU core number of this task is delayed or pended *///統計各執行緒被延期或阻塞的時間#endif#ifdef LOSCFG_SECURITY_CAPABILITY //安全能力 User *user; //程序的擁有者 UINT32 capability; //安全能力範圍 對應 CAP_SETGID#endif#ifdef LOSCFG_SECURITY_VID TimerIdMap timerIdMap;#endif#ifdef LOSCFG_DRIVERS_TZDRIVER struct file *execFile; /**< Exec bin of the process */#endif
其餘是一些安全性,統計性的能力.
以上就是程序的五臟六腑,看清楚它鴻蒙核心的影像會清晰很多!