子曰:“先進于禮樂,野人也;後進于禮樂,君子也。如用之,則吾從先進。” 《論語》:先進篇
百篇部落格系列篇.本篇為:
v47.xx 鴻蒙核心源碼分析(程序回收篇) | 臨終前如何向老祖宗托孤
程序管理相關篇為:
- v02.06 鴻蒙核心源碼分析(程序管理) | 誰在管理核心資源
- v24.03 鴻蒙核心源碼分析(程序概念) | 程序在管理哪些資源
- v45.05 鴻蒙核心源碼分析(Fork) | 一次調用,兩次傳回
- v46.05 鴻蒙核心源碼分析(特殊程序) | 老鼠生兒會打洞
- v47.02 鴻蒙核心源碼分析(程序回收) | 臨終前如何向老祖宗托孤
- v48.05 鴻蒙核心源碼分析(信号生産) | 年過半百,依然活力十足
- v49.03 鴻蒙核心源碼分析(信号消費) | 誰讓CPU連續四次換棧運作
- v71.03 鴻蒙核心源碼分析(Shell編輯) | 兩個任務,三個階段
- v72.01 鴻蒙核心源碼分析(Shell解析) | 應用窺伺核心的視窗
程序關系鍊
程序是家族式管理的,父子關系,兄弟關系,朋友關系,子女關系,甚至陌生人關系(等待你消亡)在一個程序的生命周期中都會記錄下來.用什麼來記錄呢?當然是核心最重要的膠水結構體
LOS_DL_LIST
,程序控制塊(以下簡稱
PCB
)用了8個雙向連結清單來記錄程序家族的基因關系和運作時關系.如下:
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個民族是一家,來自同一個父程序.
LOS_DL_LIST subordinateGroupList; /**< linkage in my group list */ //程序是組長時,有哪些組員程序
LOS_DL_LIST threadSiblingList; /**< List of threads under this process *///程序的線程(任務)清單
LOS_DL_LIST threadPriQueueList[OS_PRIORITY_QUEUE_NUM]; /**< The process's thread group schedules thepriority hash table */ //程序的線程組排程優先級哈希表
LOS_DL_LIST waitList; /**< The process holds the waitLits to support wait/waitpid *///程序持有等待連結清單以支援wait/waitpid
} LosProcessCB;
解讀
-
個人認為它是鴻蒙核心功能最多的一個連結清單,它遠不止字面意思阻塞連結清單這麼簡單,隻有深入解讀源碼後才能體會它真的是太會來事了,一般把它了解為阻塞連結清單就行.上面挂的是處于阻塞狀态的程序.pendList
-
孩子連結清單,所有由它fork出來的程序都挂到這個連結清單上.上面的孩子程序在死亡前會将自己從上面摘出去,轉而挂到childrenList
連結清單上.exitChildList
-
退出孩子連結清單,進入死亡程式的程序要挂到這個連結清單上,一個程序的死亡是件挺麻煩的事,程序池的數量有限,需要及時回收程序資源,但家族管理關系複雜,要去很多地方消除痕迹.尤其還有其他程序在看你笑話,等你死亡(exitChildList
/wait
)了通知它們一聲.waitpid
-
兄弟連結清單,和你同一個父親的程序都挂到了這個連結清單上.siblingList
-
朋友圈連結清單,裡面是因為興趣愛好(程序組)而挂在一起的程序,它們可以不是一個父親,不是一個祖父,但一定是同一個老祖宗(使用者态和核心态根程序).subordinateGroupList
-
線程連結清單,上面挂的是程序ID都是這個程序的線程(任務),程序和線程的關系是1:N的關系,一個線程隻能屬于一個程序.這裡要注意任務在其生命周期中是不能改所屬程序的.threadSiblingList
-
線程的排程隊列數組,一共32個,任務和程序一樣有32個優先級,排程算法的過程是先找到優先級最高的程序,在從該程序的任務隊列裡去最高的優先級任務運作.threadPriQueueList
-
是等待子程序消亡的任務連結清單,注意上面挂的是任務.任務是通過系統調用waitList
将任務挂到pid_t wait(int *status); pid_t waitpid(pid_t pid, int *status, int options);
上.鴻蒙waitpid系統調用為waitList
,稍後會講.SysWait
程序正常死亡過程
一個程序的自然消亡過程如下
//一個程序的自然消亡過程,參數是目前運作的任務
STATIC VOID OsProcessNaturalExit(LosTaskCB *runTask, UINT32 status)
{
LosProcessCB *processCB = OS_PCB_FROM_PID(runTask->processID);//通過task找到所屬PCB
LosProcessCB *parentCB = NULL;
LOS_ASSERT(!(processCB->threadScheduleMap != 0));//斷言沒有任務需要排程了,目前task是最後一個了
LOS_ASSERT(processCB->processStatus & OS_PROCESS_STATUS_RUNNING);//斷言必須為正在運作的程序
OsChildProcessResourcesFree(processCB);//釋放孩子程序的資源
#ifdef LOSCFG_KERNEL_CPUP
OsCpupClean(processCB->processID);
#endif
/* is a child process */
if (processCB->parentProcessID != OS_INVALID_VALUE) {//判斷是否有父程序
parentCB = OS_PCB_FROM_PID(processCB->parentProcessID);//擷取父程序實體
LOS_ListDelete(&processCB->siblingList);//将自己從兄弟連結清單中摘除,家人們,永别了!
if (!OsProcessExitCodeSignalIsSet(processCB)) {//是否設定了退出碼?
OsProcessExitCodeSet(processCB, status);//将程序狀态設為退出碼
}
LOS_ListTailInsert(&parentCB->exitChildList, &processCB->siblingList);//挂到父程序的孩子消亡連結清單,家人中,永别的可不止我一個.
LOS_ListDelete(&processCB->subordinateGroupList);//和志同道合的朋友們永别了,注意家裡可不一定是朋友的,所有各有連結清單.
LOS_ListTailInsert(&processCB->group->exitProcessList, &processCB->subordinateGroupList);//挂到程序組消亡連結清單,朋友中,永别的可不止我一個.
OsWaitCheckAndWakeParentProcess(parentCB, processCB);//檢查父程序的等待任務并喚醒任務,此處将會切換到其他任務運作.
OsDealAliveChildProcess(processCB);//老父親臨終向各自的祖宗托孤
processCB->processStatus |= OS_PROCESS_STATUS_ZOMBIES;//貼上僵死程序的标簽
(VOID)OsKill(processCB->parentProcessID, SIGCHLD, OS_KERNEL_KILL_PERMISSION);//以核心權限發送SIGCHLD(子程序退出)信号.
LOS_ListHeadInsert(&g_processRecyleList, &processCB->pendList);//将程序通過其阻塞節點挂入全局程序回收連結清單
OsRunTaskToDelete(runTask);//删除正在運作的任務
return;
}
LOS_Panic("pid : %u is the root process exit!\n", processCB->processID);
return;
}
- 退群,向兄弟姐妹
告别,向朋友圈(程序組)告别siblingList
.subordinateGroupList
- 留下你的死亡記錄,老父親記錄到
,朋友圈記錄到exitChildList
中.exitProcessList
- 告訴後人死亡原因
,因為OsProcessExitCodeSet
上挂的任務在等待你的死亡資訊.waitList
- 向老祖宗托孤,使用者态和核心态程序都有自己的祖宗程序(1和2号程序),老祖宗身子硬朗,最後死.所有的短命鬼程序都可以把自己的孩子委托給老祖宗照顧,老祖宗會一視同仁.
- 将自己變成了
僵屍程序.OS_PROCESS_STATUS_ZOMBIES
- 老父親跑到村口廣播這個孩子已經死亡的信号
OsKill
- 将自己挂入程序回收連結清單,等待回收任務
回收資源.ResourcesTask
- 最後删除這個正在運作的任務,很明顯其中一定會發生一次排程
OsSchedResched
//删除一個正在運作的任務 LITE_OS_SEC_TEXT VOID OsRunTaskToDelete(LosTaskCB *taskCB) { LosProcessCB *processCB = OS_PCB_FROM_PID(taskCB->processID);//拿到task所屬程序 OsTaskReleaseHoldLock(processCB, taskCB);//task還鎖 OsTaskStatusUnusedSet(taskCB);//task重置為未使用狀态,等待回收 LOS_ListDelete(&taskCB->threadList);//從程序的線程連結清單中将自己摘除 processCB->threadNumber--;//程序的活動task --,注意程序還有一個記錄總task的變量 processCB->threadCount LOS_ListTailInsert(&g_taskRecyleList, &taskCB->pendList);//将task插入回收連結清單,等待回收資源再利用 OsEventWriteUnsafe(&g_resourceEvent, OS_RESOURCE_EVENT_FREE, FALSE, NULL);//發送釋放資源的事件,事件由 OsResourceRecoveryTask 消費 OsSchedResched();//申請排程 return; }
- 但這是一個自然死亡的程序,還有很多非正常死亡在其他篇幅中已有說明.請自行翻看.非正常死亡的會産生僵屍程序.這種程序需要别的程序通過
來回收.waitpid
孤兒程序
一般情況下往往是白發人送黑發人,子程序的生命周期是要短于父程序.但因為fork之後,程序之間互相獨立,排程算法一視同仁,父子之間是弱的關系力,就什麼情況都可能發生了.核心是允許老父親先走的,如果父程序退出而它的一個或多個子程序還在運作,那麼這些子程序就被稱為孤兒程序,孤兒程序最終将被兩位老祖宗(使用者态和核心态)所收養,并由老祖宗完成對它們的狀态收集工作。
//當一個程序自然退出的時候,它的孩子程序由兩位老祖宗收養
STATIC VOID OsDealAliveChildProcess(LosProcessCB *processCB)
{
UINT32 parentID;
LosProcessCB *childCB = NULL;
LosProcessCB *parentCB = NULL;
LOS_DL_LIST *nextList = NULL;
LOS_DL_LIST *childHead = NULL;
if (!LOS_ListEmpty(&processCB->childrenList)) {//如果存在孩子程序
childHead = processCB->childrenList.pstNext;//擷取孩子連結清單
LOS_ListDelete(&(processCB->childrenList));//清空自己的孩子連結清單
if (OsProcessIsUserMode(processCB)) {//是使用者态程序
parentID = g_userInitProcess;//使用者态程序老祖宗
} else {
parentID = g_kernelInitProcess;//核心态程序老祖宗
}
for (nextList = childHead; ;) {//周遊孩子連結清單
childCB = OS_PCB_FROM_SIBLIST(nextList);//找到孩子的真身
childCB->parentProcessID = parentID;//孩子磕頭認老祖宗為爸爸
nextList = nextList->pstNext;//找下一個孩子程序
if (nextList == childHead) {//一圈下來,孩子們都磕完頭了
break;
}
}
parentCB = OS_PCB_FROM_PID(parentID);//找個老祖宗的真身
LOS_ListTailInsertList(&parentCB->childrenList, childHead);//挂到老祖宗的孩子連結清單上
}
return;
}
- 函數很簡單,都一一注釋了,老父親臨終托付後事,請各自的老祖宗照顧孩子.
- 從這裡也可以看出程序的家族管理模式,兩個家族從程序的出生到死亡負責到底.
僵屍程序
一個程序在終止時會關閉所有檔案描述符,釋放在使用者空間配置設定的記憶體,但它的
PCB
還保留着,核心在其中儲存了一些資訊:如果是正常終止則儲存着退出狀态,如果是異常終止則儲存着導緻該程序終止的信号是哪個。這個程序的父程序可以調用wait或waitpid擷取這些資訊,然後徹底清除掉這個程序。
如果一個程序已經終止,但是它的父程序尚未調用wait或waitpid對它進行清理,這時的程序狀态稱為僵屍(Zombie)程序,即 Z 程序.任何程序在剛終止時都是僵屍程序,正常情況下,僵屍程序都立刻被父程序清理了. 不正常情況下就需要手動
waitpid
清理了.
waitpid
在鴻蒙系統中,一個程序結束了,但是它的父程序沒有等待(調用
wait
waitpid
)它,那麼它将變成一個僵屍程序。通過系統調用
waitpid
可以徹底的清理掉子程序.歸還
pcb
.最終調用到
SysWait
#include <sys/wait.h>
#include "syscall.h"
pid_t waitpid(pid_t pid, int *status, int options)
{
return syscall_cp(SYS_wait4, pid, status, options, 0);
}
//等待子程序結束
int SysWait(int pid, USER int *status, int options, void *rusage)
{
(void)rusage;
return LOS_Wait(pid, status, (unsigned int)options, NULL);
}
//傳回已經終止的子程序的程序ID号,并清除僵死程序。
LITE_OS_SEC_TEXT INT32 LOS_Wait(INT32 pid, USER INT32 *status, UINT32 options, VOID *rusage)
{
(VOID)rusage;
UINT32 ret;
UINT32 intSave;
LosProcessCB *childCB = NULL;
LosProcessCB *processCB = NULL;
LosTaskCB *runTask = NULL;
ret = OsWaitOptionsCheck(options);//參數檢查,隻支援LOS_WAIT_WNOHANG
if (ret != LOS_OK) {
return -ret;
}
SCHEDULER_LOCK(intSave);
processCB = OsCurrProcessGet(); //擷取目前程序
runTask = OsCurrTaskGet(); //擷取目前任務
ret = OsWaitChildProcessCheck(processCB, pid, &childCB);//先檢查下看能不能找到參數要求的退出子程序
if (ret != LOS_OK) {
pid = -ret;
goto ERROR;
}
if (childCB != NULL) {//找到了程序
return OsWaitRecycleChildPorcess(childCB, intSave, status);//回收程序
}
//沒有找到,看是否要傳回還是去做個登記
if ((options & LOS_WAIT_WNOHANG) != 0) {//有LOS_WAIT_WNOHANG标簽
runTask->waitFlag = 0;//等待辨別置0
pid = 0;//這裡置0,是為了 return 0
goto ERROR;
}
//等待孩子程序退出
OsWaitInsertWaitListInOrder(runTask, processCB);//将目前任務挂入程序waitList連結清單
//發起排程的目的是為了讓出CPU,讓其他程序/任務運作
OsSchedResched();//發起排程
runTask->waitFlag = 0;
if (runTask->waitID == OS_INVALID_VALUE) {
pid = -LOS_ECHILD;//沒有此子程序
goto ERROR;
}
childCB = OS_PCB_FROM_PID(runTask->waitID);//擷取目前任務的等待子程序ID
if (!(childCB->processStatus & OS_PROCESS_STATUS_ZOMBIES)) {//子程序非僵死程序
pid = -LOS_ESRCH;//沒有此程序
goto ERROR;
}
//回收僵死程序
return OsWaitRecycleChildPorcess(childCB, intSave, status);
ERROR:
SCHEDULER_UNLOCK(intSave);
return pid;
}
-
是資料參數,根據不同的參數代表不同的含義,含義如下:pid
參數值 說明 pid<-1 等待程序組号為pid絕對值的任何子程序。 pid=-1 等待任何子程序,此時的waitpid()函數就退化成了普通的wait()函數。 pid=0 等待程序組号與目前程序相同的任何子程序,也就是說任何和調用waitpid()函數的程序在同一個程序組的程序。 pid>0 等待程序号為pid的子程序。
不同值代表的真正含義可以看這個函數pid
OsWaitSetFlag
//設定等待子程序退出方式方法 STATIC UINT32 OsWaitSetFlag(const LosProcessCB *processCB, INT32 pid, LosProcessCB **child) { LosProcessCB *childCB = NULL; ProcessGroup *group = NULL; LosTaskCB *runTask = OsCurrTaskGet(); UINT32 ret; if (pid > 0) {//等待程序号為pid的子程序結束 /* Wait for the child process whose process number is pid. */ childCB = OsFindExitChildProcess(processCB, pid);//看能否從退出的孩子連結清單中找到PID if (childCB != NULL) {//找到了,确實有一個已經退出的PID,注意一個程序退出時會挂到父程序的exitChildList上 goto WAIT_BACK;//直接成功傳回 } ret = OsFindChildProcess(processCB, pid);//看能否從現有的孩子連結清單中找到PID if (ret != LOS_OK) { return LOS_ECHILD;//參數程序并沒有這個PID孩子,傳回孩子程序失敗. } runTask->waitFlag = OS_PROCESS_WAIT_PRO;//設定目前任務的等待類型 runTask->waitID = pid; //目前任務要等待程序ID結束 } else if (pid == 0) {//等待同一程序組中的任何子程序 /* Wait for any child process in the same process group */ childCB = OsFindGroupExitProcess(processCB->group, OS_INVALID_VALUE);//看能否從退出的孩子連結清單中找到PID if (childCB != NULL) {//找到了,确實有一個已經退出的PID goto WAIT_BACK;//直接成功傳回 } runTask->waitID = processCB->group->groupID;//等待程序組的任意一個子程序結束 runTask->waitFlag = OS_PROCESS_WAIT_GID;//設定目前任務的等待類型 } else if (pid == -1) {//等待任意子程序 /* Wait for any child process */ childCB = OsFindExitChildProcess(processCB, OS_INVALID_VALUE);//看能否從退出的孩子連結清單中找到PID if (childCB != NULL) {//找到了,确實有一個已經退出的PID goto WAIT_BACK; } runTask->waitID = pid;//等待PID,這個PID可以和目前程序沒有任何關系 runTask->waitFlag = OS_PROCESS_WAIT_ANY;//設定目前任務的等待類型 } else { /* pid < -1 */ //等待指定程序組内為|pid|的所有子程序 /* Wait for any child process whose group number is the pid absolute value. */ group = OsFindProcessGroup(-pid);//先通過PID找到程序組 if (group == NULL) { return LOS_ECHILD; } childCB = OsFindGroupExitProcess(group, OS_INVALID_VALUE);//在程序組裡任意一個已經退出的子程序 if (childCB != NULL) { goto WAIT_BACK; } runTask->waitID = -pid;//此處用負數是為了和(pid == 0)以示差別,因為二者的waitFlag都一樣. runTask->waitFlag = OS_PROCESS_WAIT_GID;//設定目前任務的等待類型 } WAIT_BACK: *child = childCB; return LOS_OK; }
-
帶走程序退出碼,status
分成了三個部分格式如下exitCode
/* * Process exit code * 31 15 8 7 0 * | | exit code | core dump | signal | */ #define OS_PRO_EXIT_OK 0 //程序正常退出 //置程序退出碼第七位為1 STATIC INLINE VOID OsProcessExitCodeCoreDumpSet(LosProcessCB *processCB) { processCB->exitCode |= 0x80U;// 0b10000000 } //設定程序退出信号(0 ~ 7) STATIC INLINE VOID OsProcessExitCodeSignalSet(LosProcessCB *processCB, UINT32 signal) { processCB->exitCode |= signal & 0x7FU;//0b01111111 } //清除程序退出信号(0 ~ 7) STATIC INLINE VOID OsProcessExitCodeSignalClear(LosProcessCB *processCB) { processCB->exitCode &= (~0x7FU);//低7位全部清0 } //程序退出碼是否被設定過,預設是 0 ,如果 & 0x7FU 還是 0 ,說明沒有被設定過. STATIC INLINE BOOL OsProcessExitCodeSignalIsSet(LosProcessCB *processCB) { return (processCB->exitCode) & 0x7FU; } //設定程序退出号(8 ~ 15) STATIC INLINE VOID OsProcessExitCodeSet(LosProcessCB *processCB, UINT32 code) { processCB->exitCode |= ((code & 0x000000FFU) << 8U) & 0x0000FF00U; /* 8: Move 8 bits to the left, exitCode */ }
為信号位,信号處理有專門的篇幅,此處不做詳細介紹,請自行翻看,這裡僅列出部分信号含義.0 - 7
#define SIGHUP 1 //終端挂起或者控制程序終止 #define SIGINT 2 //鍵盤中斷(如break鍵被按下) #define SIGQUIT 3 //鍵盤的退出鍵被按下 #define SIGILL 4 //非法指令 #define SIGTRAP 5 //跟蹤陷阱(trace trap),啟動程序,跟蹤代碼的執行 #define SIGABRT 6 //由abort(3)發出的退出指令 #define SIGIOT SIGABRT //abort發出的信号 #define SIGBUS 7 //總線錯誤 #define SIGFPE 8 //浮點異常 #define SIGKILL 9 //常用的指令 kill 9 123 | 不能被忽略、處理和阻塞 #define SIGUSR1 10 //使用者自定義信号1 #define SIGSEGV 11 //無效的記憶體引用, 段違例(segmentation violation),程序試圖去通路其虛位址空間以外的位置 #define SIGUSR2 12 //使用者自定義信号2 #define SIGPIPE 13 //向某個非讀管道中寫入資料 #define SIGALRM 14 //由alarm(2)發出的信号,預設行為為程序終止 #define SIGTERM 15 //終止信号 #define SIGSTKFLT 16 //棧溢出 #define SIGCHLD 17 //子程序結束信号 #define SIGCONT 18 //程序繼續(曾被停止的程序) #define SIGSTOP 19 //終止程序 | 不能被忽略、處理和阻塞 #define SIGTSTP 20 //控制終端(tty)上 按下停止鍵 #define SIGTTIN 21 //程序停止,背景程序企圖從控制終端讀 #define SIGTTOU 22 //程序停止,背景程序企圖從控制終端寫 #define SIGURG 23 //I/O有緊急資料到達目前程序 #define SIGXCPU 24 //程序的CPU時間片到期 #define SIGXFSZ 25 //檔案大小的超出上限 #define SIGVTALRM 26 //虛拟時鐘逾時 #define SIGPROF 27 //profile時鐘逾時 #define SIGWINCH 28 //視窗大小改變 #define SIGIO 29 //I/O相關 #define SIGPOLL 29 // #define SIGPWR 30 //電源故障,關機 #define SIGSYS 31 //系統調用中參數錯,如系統調用号非法 #define SIGUNUSED SIGSYS //系統調用異常
-
是行為參數,提供了一些另外的選項來控制waitpid()函數的行為。options
鴻蒙目前隻支援了LOS_WAIT_WNOHANG模式,核心源碼中雖有鴻蒙支援 LOS_WAIT_WNOHANG 支援 如果沒有孩子程序退出,則立即傳回,而不是阻塞在這個函數上等待;如果結束了,則傳回該子程序的程序号。 LOS_WAIT_WUNTRACED 不支援 報告終止或停止的子程序的狀态 LOS_WAIT_WCONTINUED
和LOS_WAIT_WUNTRACED
的實作痕迹,但是整體閱讀下來比較亂,應該是沒有寫好.LOS_WAIT_WCONTINUED
百篇部落格分析.深挖核心地基
- 給鴻蒙核心源碼加注釋過程中,整理出以下文章。内容立足源碼,常以生活場景打比方盡可能多的将核心知識點置入某種場景,具有畫面感,容易了解記憶。說别人能聽得懂的話很重要! 百篇部落格絕不是百度教條式的在說一堆诘屈聱牙的概念,那沒什麼意思。更希望讓核心變得栩栩如生,倍感親切.确實有難度,自不量力,但已經出發,回頭已是不可能的了。 😛
- 與代碼有bug需不斷debug一樣,文章和注解内容會存在不少錯漏之處,請多包涵,但會反複修正,持續更新,v**.xx 代表文章序号和修改的次數,精雕細琢,言簡意赅,力求打造精品内容。
按功能子產品:
基礎工具 | 加載運作 | 程序管理 | 編譯建構 |
---|---|---|---|
雙向連結清單 位圖管理 用棧方式 定時器 原子操作 時間管理 | ELF格式 ELF解析 靜态連結 重定位 程序映像 | 程序概念 Fork 特殊程序 程序回收 信号生産 信号消費 Shell編輯 Shell解析 | 編譯環境 編譯過程 環境腳本 建構工具 gn應用 忍者ninja |
程序通訊 | 記憶體管理 | 前因後果 | 任務管理 |
自旋鎖 互斥鎖 信号量 事件控制 消息隊列 | 記憶體配置設定 記憶體彙編 記憶體映射 記憶體規則 實體記憶體 | 總目錄 排程故事 記憶體主奴 源碼注釋 源碼結構 靜态站點 | 時鐘任務 任務排程 排程隊列 排程機制 線程概念 并發并行 CPU 系統調用 任務切換 |
檔案系統 | 硬體架構 | ||
檔案概念 索引節點 挂載目錄 根檔案系統 字元裝置 VFS 檔案句柄 管道檔案 | 彙編基礎 彙編傳參 工作模式 寄存器 異常接管 彙編彙總 中斷切換 中斷概念 中斷管理 |
百萬漢字注解.精讀核心源碼
四大碼倉中文注解 . 定期同步官方代碼
鴻蒙研究站( weharmonyos ) | 每天死磕一點點,原創不易,歡迎轉載,請注明出處。若能支援點贊更好,感謝每一份支援。