天天看點

v48.05 鴻蒙核心源碼分析(信号生産篇) | 信号安裝和發送過程是怎樣的? | 百篇部落格分析OpenHarmony源碼

德行:顔淵,闵子骞,冉伯牛,仲弓。言語:宰我,子貢。政事:冉有,季路。文學:子遊,子夏。 《論語》:先進篇

v48.05 鴻蒙核心源碼分析(信号生産篇) | 信号安裝和發送過程是怎樣的? | 百篇部落格分析OpenHarmony源碼

百篇部落格系列篇.本篇為:

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():用于向程序自身發送信号;

信号與程序的關系

主要是通過系統調用

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] 對應

    sigShare

    的[0 ~ 63]位,是以中間會差一個.記住這點,後續代碼會提到.
  • 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

      鴻蒙目前隻支援信号處理函數——普通版,

      sa_handler

      表示自定義信号處理函數,該函數傳回值為void,可以帶一個int參數,通過參數可以得知目前信号的編号,這樣就可以用同一個函數處理多種信号。
    • 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

    ,是以發給程序的信号最終還是需要分發給具體任務來處理.是以能想到的是關于任務部分會更複雜.
  • context

    信号處理很複雜的原因在于信号的發起在使用者空間,發送需要系統調用,而處理信号的函數又是使用者空間提供的, 是以需要反複的切換任務上下文.而且還有硬中斷的問題,比如 ctrl + c ,需要從硬中斷中回調使用者空間的信号處理函數,處理完了再回到核心空間,最後回到使用者空間.沒聽懂吧,我自己都說暈了,是以需要專門的一篇來說清楚信号的處理問題.本篇不展開說.
  • 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

檔案句柄

管道檔案

彙編基礎

彙編傳參

工作模式

寄存器

異常接管

彙編彙總

中斷切換

中斷概念

中斷管理

百萬漢字注解.精讀核心源碼

四大碼倉中文注解 . 定期同步官方代碼

v48.05 鴻蒙核心源碼分析(信号生産篇) | 信号安裝和發送過程是怎樣的? | 百篇部落格分析OpenHarmony源碼

鴻蒙研究站( weharmonyos ) | 每天死磕一點點,原創不易,歡迎轉載,請注明出處。若能支援點贊更好,感謝每一份支援。

繼續閱讀