德行:顔淵,闵子骞,冉伯牛,仲弓。言語:宰我,子貢。政事:冉有,季路。文學:子遊,子夏。 《論語》:先進篇
百篇部落格系列篇.本篇為:
v48.xx 鴻蒙核心源碼分析(信号生産篇) | 年過半百,依然活力十足
程序管理相關篇為:
- v02.06 鴻蒙核心源碼分析(程序管理) | 誰在管理核心資源
- v24.03 鴻蒙核心源碼分析(程序概念) | 程序在管理哪些資源
- v45.05 鴻蒙核心源碼分析(Fork) | 一次調用,兩次傳回
- v46.05 鴻蒙核心源碼分析(特殊程序) | 老鼠生兒會打洞
- v47.02 鴻蒙核心源碼分析(程序回收) | 臨終前如何向老祖宗托孤
- v48.05 鴻蒙核心源碼分析(信号生産) | 年過半百,依然活力十足
- v49.03 鴻蒙核心源碼分析(信号消費) | 誰讓CPU連續四次換棧運作
- v71.03 鴻蒙核心源碼分析(Shell編輯) | 兩個任務,三個階段
- v72.01 鴻蒙核心源碼分析(Shell解析) | 應用窺伺核心的視窗
信号生産
關于信号篇,本隻想寫一篇,但發現把它想簡單了,内容不多,難度極大.整理了好長時間,了解了為何<<深入了解linux核心>>要單獨為它開一章,原因有二
- 信号相關的結構體多,而且還容易搞混.是以看本篇要注意結構體的名字和作用.
- 系統調用太多了,涉及面廣,信号的來源分硬體和軟體.相當于軟中斷和硬中斷,這就會涉及到彙編代碼,但信号的處理函數又在使用者空間,CPU是禁止核心态執行使用者态代碼的,是以運作過程需在使用者空間和核心空間來回的折騰,頻繁的切換上下文.
信号思想來自Unix,它老人家已經五十多歲了,但很有活力,許多方面幾乎沒發生大的變化.信号可以由核心産生,也可以由使用者程序産生,并由核心傳送給特定的程序或線程(組),若這個程序定義了自己的信号處理程式,則調用這個程式去處理信号,否則則執行預設的程式或者忽略.
信号為系統提供了一種程序間異步通訊的方式,一個程序不必通過任何操作來等待信号的到達。事實上,程序也不可能知道信号到底什麼時候到達。一般來說,隻需使用者程序提供信号處理函數,核心會想方設法調用信号處理函數,網上查閱了很多的關于信号的資料.個人想換個視角去看信号.把異步過程了解為生産者(安裝和發送信号)和消費者(捕捉和處理信号)兩個過程.鑒于此,系列篇将分成兩篇說明,本篇為信号生産篇:
- v48.xx (信号生産篇) | 年過半百,依然活力十足
- v49.xx (信号消費篇) | 誰讓CPU連續四次換棧運作
信号分類
每個信号都有一個名字和編号,這些名字都以
SIG
開頭,例如
SIGQUIT
、
SIGCHLD
等等。
信号定義在signal.h頭檔案中,信号名都定義為正整數。
具體的信号名稱可以使用
kill -l
來檢視信号的名字以及序号,信号是從1開始編号的,不存在0号信号。不過
kill
對于信号0有特殊的應用。啥用呢? 可用來查詢程序是否還在. 敲下
kill 0 pid
就知道了.
信号分為兩大類:可靠信号與不可靠信号,前32種信号為不可靠信号,後32種為可靠信号。
- 不可靠信号: 也稱為非實時信号,不支援排隊,信号可能會丢失, 比如發送多次相同的信号, 程序隻能收到一次. 信号值取值區間為1~31;
- 可靠信号: 也稱為實時信号,支援排隊, 信号不會丢失, 發多少次, 就可以收到多少次. 信号值取值區間為32~64
#define SIGHUP 1 //終端挂起或者控制程序終止
#define SIGINT 2 //鍵盤中斷(ctrl + c)
#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//不使用
#define _NSIG 65
信号來源
信号來源分為硬體類和軟體類:
- 硬體類
- 使用者輸入:比如在終端上按下組合鍵
,産生ctrl+C
信号;SIGINT
- 硬體異常:CPU檢測到記憶體非法通路等異常,通知核心生成相應信号,并發送給發生事件的程序;
- 使用者輸入:比如在終端上按下組合鍵
- 軟體類
- 通過系統調用,發送signal信号:
,kill()
raise()
sigqueue()
alarm()
setitimer()
abort()
-
指令就是一個發送信号的工具,用于向程序或程序組發送信号.例如:kill
(kill 9 PID
)來殺死SIGKILL
程序.PID
- sigqueue():隻能向一個程序發送信号,不能向程序組發送信号;主要針對實時信号提出,與sigaction()組合使用,當然也支援非實時信号的發送;
- alarm():用于調用程序指定時間後發出SIGALARM信号;
- setitimer():設定定時器,計時達到後給程序發送SIGALRM信号,功能比alarm更強大;
- abort():向程序發送SIGABORT信号,預設程序會異常退出。
- raise():用于向程序自身發送信号;
-
- 通過系統調用,發送signal信号:
信号與程序的關系
主要是通過系統調用
sigaction
将使用者态信号處理函數注冊到PCB儲存.所有程序的任務都共用這個信号注冊函數
sigHandler
,在信号的消費階段核心用一種特殊的方式'回調'它.
typedef struct ProcessCB {//PCB中關于信号的資訊
UINTPTR sigHandler; /**< signal handler */ //捕捉信号後的處理函數
sigset_t sigShare; /**< signal share bit */ //信号共享位,64個信号各站一位
}LosProcessCB;
typedef unsigned _Int64 sigset_t; //一個64位的變量,每個信号代表一位.
struct sigaction {//信号處理機制結構體
union {
void (*sa_handler)(int); //信号處理函數——普通版
void (*sa_sigaction)(int, siginfo_t *, void *);//信号處理函數——進階版
} __sa_handler;
sigset_t sa_mask;//指定信号處理程式執行過程中需要阻塞的信号;
int sa_flags; //标示位
// SA_RESTART:使被信号打斷的syscall重新發起。
// SA_NOCLDSTOP:使父程序在它的子程序暫停或繼續運作時不會收到 SIGCHLD 信号。
// SA_NOCLDWAIT:使父程序在它的子程序退出時不會收到SIGCHLD信号,這時子程序如果退出也不會成為僵 屍程序。
// SA_NODEFER:使對信号的屏蔽無效,即在信号處理函數執行期間仍能發出這個信号。
// SA_RESETHAND:信号處理之後重新設定為預設的處理方式。
// SA_SIGINFO:使用sa_sigaction成員而不是sa_handler作為信号處理函數。
void (*sa_restorer)(void);
};
typedef struct sigaction sigaction_t;
解讀
- 每個信号都對應一個位. 信号從1開始編号 [1 ~ 64] 對應
的[0 ~ 63]位,是以中間會差一個.記住這點,後續代碼會提到.sigShare
-
信号處理函數的注冊過程,由系統調用sigHandler
(使用者空間) ->sigaction
(核心空間)完成綁定動作.OsSigAction
#include <signal.h> int sigaction(int signo, const struct sigaction *act, struct sigaction *oact); int OsSigAction(int sig, const sigaction_t *act, sigaction_t *oact) { UINTPTR addr; sigaction_t action; if (!GOOD_SIGNO(sig) || sig < 1 || act == NULL) { return -EINVAL; } //将資料從使用者空間拷貝到核心空間 if (LOS_ArchCopyFromUser(&action, act, sizeof(sigaction_t)) != LOS_OK) { return -EFAULT; } if (sig == SIGSYS) {//鴻蒙此處通過錯誤的系統調用 來安裝信号處理函數,有點巧妙. addr = OsGetSigHandler();//擷取程序信号處理函數 if (addr == 0) {//程序沒有設定信号處理函數時 OsSetSigHandler((unsigned long)(UINTPTR)action.sa_handler);//設定程序信号處理函數——普通版 return LOS_OK; } return -EINVAL; } return LOS_OK; }
-
第一個參數是要安裝的信号; 第二個參數與sigaction函數同名的結構體,這裡會讓人很懵,函數名和結構體一直,沒明白為毛要這麼搞? 結構體内定義了信号處理方法;第三個為輸出參數,将信号的目前的sigaction結構帶回.但鴻蒙顯然沒有認真對待第三個參數.把sigaction(...)
實作給閹割了.musl
- 對結構體的
鴻蒙目前隻支援信号處理函數——普通版,sigaction
表示自定義信号處理函數,該函數傳回值為void,可以帶一個int參數,通過參數可以得知目前信号的編号,這樣就可以用同一個函數處理多種信号。sa_handler
-
指定信号處理程式執行過程中需要阻塞的信号。sa_mask
-
字段包含一些選項,具體看注釋sa_flags
-
是實時信号的處理函數,sa_sigaction
二選一.鴻蒙暫時不支援這種方式.union
-
信号與任務的關系
typedef struct {//TCB中關于信号的資訊
sig_cb sig; //信号控制塊,用于異步通信,類似于 linux singal子產品
} LosTaskCB;
typedef struct {//信号控制塊(描述符)
sigset_t sigFlag; //不屏蔽的信号标簽集
sigset_t sigPendFlag; //信号阻塞标簽集,記錄因哪些信号被阻塞
sigset_t sigprocmask; /* Signals that are blocked */ //程序屏蔽了哪些信号
sq_queue_t sigactionq; //信号捕捉隊列
LOS_DL_LIST waitList; //等待連結清單,上面挂的是等待信号到來的任務, 可查找 OsTaskWait(&sigcb->waitList, timeout, TRUE) 了解
sigset_t sigwaitmask; /* Waiting for pending signals */ //任務在等待阻塞信号
siginfo_t sigunbinfo; /* Signal info when task unblocked */ //任務解鎖時的信号資訊
sig_switch_context context; //信号切換上下文, 用于儲存切換現場, 比如發生系統調用時的傳回,涉及同一個任務的兩個棧進行切換
} sig_cb;
- 系列篇已多次說過,程序隻是管理資源的容器,真正讓cpu幹活的是任務
,是以發給程序的信号最終還是需要分發給具體任務來處理.是以能想到的是關于任務部分會更複雜.task
-
信号處理很複雜的原因在于信号的發起在使用者空間,發送需要系統調用,而處理信号的函數又是使用者空間提供的, 是以需要反複的切換任務上下文.而且還有硬中斷的問題,比如 ctrl + c ,需要從硬中斷中回調使用者空間的信号處理函數,處理完了再回到核心空間,最後回到使用者空間.沒聽懂吧,我自己都說暈了,是以需要專門的一篇來說清楚信号的處理問題.本篇不展開說.context
-
結構體是任務處理信号的結構體,要響應,屏蔽哪些信号等等都由它完成,這個結構體雖不複雜,但是很繞,很難搞清楚它們之間的差別.筆者是經過一番痛苦的閱讀了解後才明白各自的含義.并想通過用打比方的例子試圖讓大家明白.sig_cb
- 以下用追女孩打比方了解.任務相當于某個男,沒錯說的就是螢幕前的你,除了苦逼的碼農誰會有耐心能堅持看到這裡.64個信号對應64個女孩.允許一男同時追多個女孩,女孩也可同時被多個男追.女孩也可以主動追男的.了解如下:
-
等待信号的任務連結清單,上面挂的是因等待信号而被阻塞的任務.衆男在排隊追各自心愛的女孩們,處于無所事事的挂起的狀态,等待女孩們的出現.waitList
-
任務在等待的信号集合,隻有這些信号能喚醒任務.相當于列出喜歡的各位女孩,隻要出現一位就能讓你滿血複活.sigwaitmask
-
指任務對哪些信号不感冒.來了也不處理.相當于列出不喜歡的各位女孩,請她們别來騷擾你,嘚瑟.sigprocmask
-
信号到達但并未喚醒任務.相當于喜歡你的女孩來追你,但她不在你喜歡的清單内,結果是不搭理人家繼續等喜歡的出現.sigPendFlag
-
記錄不屏蔽的信号集合,相當于你并不反感的女孩們.記錄來過的那些女孩(除掉你不喜歡的).sigFlag
信号發送過程
使用者程序調用
kill()
的過程如下:
kill(pid_t pid, int sig) - 系統調用
| 使用者空間
---------------------------------------------------------------------------------------
| 核心空間
SysKill(...)
|---> OsKillLock(...)
|---> OsKill(.., OS_USER_KILL_PERMISSION)
|---> OsDispatch() //鑒權,向程序發送信号
|---> OsSigProcessSend() //選擇任務發送信号
|---> OsSigProcessForeachChild(..,ForEachTaskCB handler,..)
|---> SigProcessKillSigHandler() //處理 SIGKILL
|---> OsTaskWake() //喚醒所有等待任務
|---> OsSigEmptySet() //清空信号等待集
|---> SigProcessSignalHandler()
|---> OsTcbDispatch() //向目标任務發送信号
|---> OsTaskWake() //喚醒任務
|---> OsSigEmptySet() //清空信号等待集
流程
- 通過 系統調用
陷入核心空間kill
- 因為是使用者态程序,使用
權限發送信号OS_USER_KILL_PERMISSION
#define OS_KERNEL_KILL_PERMISSION 0U //核心态 kill 權限 #define OS_USER_KILL_PERMISSION 3U //使用者态 kill 權限
- 鑒權之後程序輪詢任務組,向目标任務發送信号.這裡分三種情況:
-
信号,将所有等待任務喚醒,拉入就緒隊列等待被排程執行,并情況信号等待集SIGKILL
- 非
信号時,将通過SIGKILL
和sigwaitmask
過濾,找到一個任務向它發送信号sigprocmask
.OsTcbDispatch
-
代碼細節
int OsKill(pid_t pid, int sig, int permission)
{
siginfo_t info;
int ret;
/* Make sure that the para is valid */
if (!GOOD_SIGNO(sig) || pid < 0) {//有效信号 [0,64]
return -EINVAL;
}
if (OsProcessIDUserCheckInvalid(pid)) {//檢查參數程序
return -ESRCH;
}
/* Create the siginfo structure */ //建立信号結構體
info.si_signo = sig; //信号編号
info.si_code = SI_USER; //來自使用者程序信号
info.si_value.sival_ptr = NULL;
/* Send the signal */
ret = OsDispatch(pid, &info, permission);//發送信号
return ret;
}
//信号分發
int OsDispatch(pid_t pid, siginfo_t *info, int permission)
{
LosProcessCB *spcb = OS_PCB_FROM_PID(pid);//找到這個程序
if (OsProcessIsUnused(spcb)) {//程序是否還在使用,不一定是目前程序但必須是個有效程序
return -ESRCH;
}
#ifdef LOSCFG_SECURITY_CAPABILITY //啟用能力安全模式
LosProcessCB *current = OsCurrProcessGet();//擷取目前程序
/* If the process you want to kill had been inactive, but still exist. should return LOS_OK */
if (OsProcessIsInactive(spcb)) {//如果要終止的程序處于非活動狀态,但仍然存在,應該傳回OK
return LOS_OK;
}
/* Kernel process always has kill permission and user process should check permission *///核心程序總是有kill權限,使用者程序需要檢查權限
if (OsProcessIsUserMode(current) && !(current->processStatus & OS_PROCESS_FLAG_EXIT)) {//使用者程序檢查能力範圍
if ((current != spcb) && (!IsCapPermit(CAP_KILL)) && (current->user->userID != spcb->user->userID)) {
return -EPERM;
}
}
#endif
if ((permission == OS_USER_KILL_PERMISSION) && (OsSignalPermissionToCheck(spcb) < 0)) {
return -EPERM;
}
return OsSigProcessSend(spcb, info);//給參數程序發送信号
}
//給參數程序發送參數信号
int OsSigProcessSend(LosProcessCB *spcb, siginfo_t *sigInfo)
{
int ret;
struct ProcessSignalInfo info = {
.sigInfo = sigInfo, //信号内容
.defaultTcb = NULL, //以下四個值将在OsSigProcessForeachChild中根據條件完善
.unblockedTcb = NULL,
.awakenedTcb = NULL,
.receivedTcb = NULL
};
//總之是要從程序中找個至少一個任務來接受這個信号,優先級
//awakenedTcb > receivedTcb > unblockedTcb > defaultTcb
/* visit all taskcb and dispatch signal */ //通路所有任務和分發信号
if ((info.sigInfo != NULL) && (info.sigInfo->si_signo == SIGKILL)) {//需要幹掉程序時 SIGKILL = 9, #linux kill 9 14
(void)OsSigProcessForeachChild(spcb, SigProcessKillSigHandler, &info);//程序要被幹掉了,通知所有task做善後處理
OsSigAddSet(&spcb->sigShare, info.sigInfo->si_signo);
OsWaitSignalToWakeProcess(spcb);//等待信号喚醒程序
return 0;
} else {
ret = OsSigProcessForeachChild(spcb, SigProcessSignalHandler, &info);//程序通知所有task處理信号
}
if (ret < 0) {
return ret;
}
SigProcessLoadTcb(&info, sigInfo);
return 0;
}
//讓程序的每一個task執行參數函數
int OsSigProcessForeachChild(LosProcessCB *spcb, ForEachTaskCB handler, void *arg)
{
int ret;
/* Visit the main thread last (if present) */
LosTaskCB *taskCB = NULL;//周遊程序的 threadList 連結清單,裡面存放的都是task節點
LOS_DL_LIST_FOR_EACH_ENTRY(taskCB, &(spcb->threadSiblingList), LosTaskCB, threadList) {//周遊程序的任務清單
ret = handler(taskCB, arg);//回調參數函數
OS_RETURN_IF(ret != 0, ret);//這個宏的意思就是隻有ret = 0時,啥也不處理.其餘就傳回 ret
}
return LOS_OK;
}
- 如果是
信号,讓SIGKILL
的所有任務執行spcb
函數,檢視旗下的所有任務是否又在等待這個信号的,如果有就将任務喚醒,放在就緒隊列等待被排程執行.SigProcessKillSigHandler
//程序收到 SIGKILL 信号後,通知任務tcb處理. static int SigProcessKillSigHandler(LosTaskCB *tcb, void *arg) { struct ProcessSignalInfo *info = (struct ProcessSignalInfo *)arg;//轉參 if ((tcb != NULL) && (info != NULL) && (info->sigInfo != NULL)) {//程序有信号 sig_cb *sigcb = &tcb->sig; if (!LOS_ListEmpty(&sigcb->waitList) && OsSigIsMember(&sigcb->sigwaitmask, info->sigInfo->si_signo)) {//如果任務在等待這個信号 OsTaskWake(tcb);//喚醒這個任務,加入程序的就緒隊列,并不申請排程 OsSigEmptySet(&sigcb->sigwaitmask);//清空信号等待位,不等任何信号了.因為這是SIGKILL信号 } } return 0; }
-
SIGKILL
spcb
函數SigProcessSignalHandler
static int SigProcessSignalHandler(LosTaskCB *tcb, void *arg) { struct ProcessSignalInfo *info = (struct ProcessSignalInfo *)arg;//先把參數解出來 int ret; int isMember; if (tcb == NULL) { return 0; } /* If the default tcb is not setted, then set this one as default. */ if (!info->defaultTcb) {//如果沒有預設發送方的任務,即預設參數任務. info->defaultTcb = tcb; } isMember = OsSigIsMember(&tcb->sig.sigwaitmask, info->sigInfo->si_signo);//任務是否在等待這個信号 if (isMember && (!info->awakenedTcb)) {//是在等待,并尚未向該任務時發送信号時 /* This means the task is waiting for this signal. Stop looking for it and use this tcb. * The requirement is: if more than one task in this task group is waiting for the signal, * then only one indeterminate task in the group will receive the signal. */ ret = OsTcbDispatch(tcb, info->sigInfo);//發送信号,注意這是給其他任務發送信号,tcb不是目前任務 OS_RETURN_IF(ret < 0, ret);//這種寫法很有意思 /* set this tcb as awakenedTcb */ info->awakenedTcb = tcb; OS_RETURN_IF(info->receivedTcb != NULL, SIG_STOP_VISIT); /* Stop search */ } /* Is this signal unblocked on this thread? */ isMember = OsSigIsMember(&tcb->sig.sigprocmask, info->sigInfo->si_signo);//任務是否屏蔽了這個信号 if ((!isMember) && (!info->receivedTcb) && (tcb != info->awakenedTcb)) {//沒有屏蔽,有喚醒任務沒有接收任務. /* if unblockedTcb of this signal is not setted, then set it. */ if (!info->unblockedTcb) { info->unblockedTcb = tcb; } ret = OsTcbDispatch(tcb, info->sigInfo);//向任務發送信号 OS_RETURN_IF(ret < 0, ret); /* set this tcb as receivedTcb */ info->receivedTcb = tcb;//設定這個任務為接收任務 OS_RETURN_IF(info->awakenedTcb != NULL, SIG_STOP_VISIT); /* Stop search */ } return 0; /* Keep searching */ }
- 函數的意思是,當程序中有多個任務在等待這個信号時,發送信号給第一個等待的任務
awakenedTcb
- 如果沒有任務在等待信号,那就從不屏蔽這個信号的任務集中随機找一個
接受信号.receivedTcb
- 隻要不屏蔽
就有值,随機的.unblockedTcb
- 如果上面的都不滿足,信号發送給
defaultTcb
- 尋找發送任務的優先級是
>awakenedTcb
receivedTcb
unblockedTcb
defaultTcb
- 函數的意思是,當程序中有多個任務在等待這個信号時,發送信号給第一個等待的任務
信号相關函數
信号集操作函數
- sigemptyset(sigset_t *set):信号集全部清0;
- sigfillset(sigset_t *set): 信号集全部置1,則信号集包含linux支援的64種信号;
- sigaddset(sigset_t *set, int signum):向信号集中加入signum信号;
- sigdelset(sigset_t *set, int signum):向信号集中删除signum信号;
- sigismember(const sigset_t *set, int signum):判定信号signum是否存在信号集中。
信号阻塞函數
- sigprocmask(int how, const sigset_t *set, sigset_t *oldset)); 不同how參數,實作不同功能
- SIG_BLOCK:将set指向信号集中的信号,添加到程序阻塞信号集;
- SIG_UNBLOCK:将set指向信号集中的信号,從程序阻塞信号集删除;
- SIG_SETMASK:将set指向信号集中的信号,設定成程序阻塞信号集;
- sigpending(sigset_t *set)):擷取已發送到程序,卻被阻塞的所有信号;
- sigsuspend(const sigset_t *mask)):用mask代替程序的原有掩碼,并暫停程序執行,直到收到信号再恢複原有掩碼并繼續執行程序。
百篇部落格分析.深挖核心地基
- 給鴻蒙核心源碼加注釋過程中,整理出以下文章。内容立足源碼,常以生活場景打比方盡可能多的将核心知識點置入某種場景,具有畫面感,容易了解記憶。說别人能聽得懂的話很重要! 百篇部落格絕不是百度教條式的在說一堆诘屈聱牙的概念,那沒什麼意思。更希望讓核心變得栩栩如生,倍感親切.确實有難度,自不量力,但已經出發,回頭已是不可能的了。 😛
- 與代碼有bug需不斷debug一樣,文章和注解内容會存在不少錯漏之處,請多包涵,但會反複修正,持續更新,v**.xx 代表文章序号和修改的次數,精雕細琢,言簡意赅,力求打造精品内容。
按功能子產品:
基礎工具 | 加載運作 | 程序管理 | 編譯建構 |
---|---|---|---|
雙向連結清單 位圖管理 用棧方式 定時器 原子操作 時間管理 | ELF格式 ELF解析 靜态連結 重定位 程序映像 | 程序概念 Fork 特殊程序 程序回收 信号消費 Shell編輯 Shell解析 | 編譯環境 編譯過程 環境腳本 建構工具 gn應用 忍者ninja |
程序通訊 | 記憶體管理 | 前因後果 | 任務管理 |
自旋鎖 互斥鎖 信号量 事件控制 消息隊列 | 記憶體配置設定 記憶體彙編 記憶體映射 記憶體規則 實體記憶體 | 總目錄 排程故事 記憶體主奴 源碼注釋 源碼結構 靜态站點 | 時鐘任務 任務排程 排程隊列 排程機制 線程概念 并發并行 CPU 系統調用 任務切換 |
檔案系統 | 硬體架構 | ||
檔案概念 索引節點 挂載目錄 根檔案系統 字元裝置 VFS 檔案句柄 管道檔案 | 彙編基礎 彙編傳參 工作模式 寄存器 異常接管 彙編彙總 中斷切換 中斷概念 中斷管理 |
百萬漢字注解.精讀核心源碼
四大碼倉中文注解 . 定期同步官方代碼
鴻蒙研究站( weharmonyos ) | 每天死磕一點點,原創不易,歡迎轉載,請注明出處。若能支援點贊更好,感謝每一份支援。