精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

鴻蒙內(nèi)核源碼分析:如何安裝和發(fā)送信號(hào)?

鴻蒙系統(tǒng)HarmonyOS ? 來(lái)源:my.oschina ? 作者:鴻蒙內(nèi)核源碼分析 ? 2021-04-23 17:27 ? 次閱讀

信號(hào)生產(chǎn)

關(guān)于信號(hào)篇,本只想寫(xiě)一篇,但發(fā)現(xiàn)把它想簡(jiǎn)單了,內(nèi)容不多,難度極大.整理了好長(zhǎng)時(shí)間,理解了為何<<深入理解linux內(nèi)核>>要單獨(dú)為它開(kāi)一章,原因有二

信號(hào)相關(guān)的結(jié)構(gòu)體多,而且還容易搞混.所以看本篇要注意結(jié)構(gòu)體的名字和作用.

系統(tǒng)調(diào)用太多了,涉及面廣,信號(hào)的來(lái)源分硬件和軟件.相當(dāng)于軟中斷和硬中斷,這就會(huì)涉及到匯編代碼,但信號(hào)的處理函數(shù)又在用戶空間,CPU是禁止內(nèi)核態(tài)執(zhí)行用戶態(tài)代碼的,所以運(yùn)行過(guò)程需在用戶空間和內(nèi)核空間來(lái)回的折騰,頻繁的切換上下文.

信號(hào)思想來(lái)自Unix,在發(fā)展了50年之后,許多方面都沒(méi)有發(fā)生太大的變化.信號(hào)可以由內(nèi)核產(chǎn)生,也可以由用戶進(jìn)程產(chǎn)生,并由內(nèi)核傳送給特定的進(jìn)程或線程(組),若這個(gè)進(jìn)程定義了自己的信號(hào)處理程序,則調(diào)用這個(gè)程序去處理信號(hào),否則則執(zhí)行默認(rèn)的程序或者忽略.

信號(hào)為系統(tǒng)提供了一種進(jìn)程間異步通訊的方式,一個(gè)進(jìn)程不必通過(guò)任何操作來(lái)等待信號(hào)的到達(dá)。事實(shí)上,進(jìn)程也不可能知道信號(hào)到底什么時(shí)候到達(dá)。一般來(lái)說(shuō),只需用戶進(jìn)程提供信號(hào)處理函數(shù),內(nèi)核會(huì)想方設(shè)法調(diào)用信號(hào)處理函數(shù),網(wǎng)上查閱了很多的關(guān)于信號(hào)的資料.個(gè)人想換個(gè)視角去看信號(hào).把異步過(guò)程理解為生產(chǎn)者(安裝和發(fā)送信號(hào))和消費(fèi)者(捕捉和處理信號(hào))兩個(gè)過(guò)程.鑒于此,系列篇將分成兩篇說(shuō)明,本篇為信號(hào)生產(chǎn)篇

信號(hào)分類(lèi)

每個(gè)信號(hào)都有一個(gè)名字和編號(hào),這些名字都以SIG開(kāi)頭,例如SIGQUIT、SIGCHLD等等。 信號(hào)定義在signal.h頭文件中,信號(hào)名都定義為正整數(shù)。 具體的信號(hào)名稱(chēng)可以使用kill -l來(lái)查看信號(hào)的名字以及序號(hào),信號(hào)是從1開(kāi)始編號(hào)的,不存在0號(hào)信號(hào)。不過(guò)kill對(duì)于信號(hào)0有特殊的應(yīng)用。啥用呢? 可用來(lái)查詢進(jìn)程是否還在. 敲下kill 0 pid就知道了.

信號(hào)分為兩大類(lèi):可靠信號(hào)與不可靠信號(hào),前32種信號(hào)為不可靠信號(hào),后32種為可靠信號(hào)。

不可靠信號(hào): 也稱(chēng)為非實(shí)時(shí)信號(hào),不支持排隊(duì),信號(hào)可能會(huì)丟失, 比如發(fā)送多次相同的信號(hào), 進(jìn)程只能收到一次. 信號(hào)值取值區(qū)間為1~31;

可靠信號(hào): 也稱(chēng)為實(shí)時(shí)信號(hào),支持排隊(duì), 信號(hào)不會(huì)丟失, 發(fā)多少次, 就可以收到多少次. 信號(hào)值取值區(qū)間為32~64

  #define SIGHUP    1	//終端掛起或者控制進(jìn)程終止
  #define SIGINT    2	//鍵盤(pán)中斷(ctrl + c)
  #define SIGQUIT   3	//鍵盤(pán)的退出鍵被按下
  #define SIGILL    4	//非法指令
  #define SIGTRAP   5	//跟蹤陷阱(trace trap),啟動(dòng)進(jìn)程,跟蹤代碼的執(zhí)行
  #define SIGABRT   6	//由abort(3)發(fā)出的退出指令
  #define SIGIOT    SIGABRT //abort發(fā)出的信號(hào)
  #define SIGBUS    7	//總線錯(cuò)誤 
  #define SIGFPE    8	//浮點(diǎn)異常
  #define SIGKILL   9	//常用的命令 kill 9 123 | 不能被忽略、處理和阻塞
  #define SIGUSR1   10	//用戶自定義信號(hào)1 
  #define SIGSEGV   11	//無(wú)效的內(nèi)存引用, 段違例(segmentation     violation),進(jìn)程試圖去訪問(wèn)其虛地址空間以外的位置 
  #define SIGUSR2   12	//用戶自定義信號(hào)2
  #define SIGPIPE   13	//向某個(gè)非讀管道中寫(xiě)入數(shù)據(jù) 
  #define SIGALRM   14	//由alarm(2)發(fā)出的信號(hào),默認(rèn)行為為進(jìn)程終止
  #define SIGTERM   15	//終止信號(hào)
  #define SIGSTKFLT 16	//棧溢出
  #define SIGCHLD   17	//子進(jìn)程結(jié)束信號(hào)
  #define SIGCONT   18	//進(jìn)程繼續(xù)(曾被停止的進(jìn)程)
  #define SIGSTOP   19	//終止進(jìn)程  	 | 不能被忽略、處理和阻塞
  #define SIGTSTP   20	//控制終端(tty)上 按下停止鍵
  #define SIGTTIN   21	//進(jìn)程停止,后臺(tái)進(jìn)程企圖從控制終端讀
  #define SIGTTOU   22	//進(jìn)程停止,后臺(tái)進(jìn)程企圖從控制終端寫(xiě)
  #define SIGURG    23	//I/O有緊急數(shù)據(jù)到達(dá)當(dāng)前進(jìn)程
  #define SIGXCPU   24	//進(jìn)程的CPU時(shí)間片到期
  #define SIGXFSZ   25	//文件大小的超出上限
  #define SIGVTALRM 26	//虛擬時(shí)鐘超時(shí)
  #define SIGPROF   27	//profile時(shí)鐘超時(shí)
  #define SIGWINCH  28	//窗口大小改變
  #define SIGIO     29	//I/O相關(guān)
  #define SIGPOLL   29	//
  #define SIGPWR    30	//電源故障,關(guān)機(jī)
  #define SIGSYS    31	//系統(tǒng)調(diào)用中參數(shù)錯(cuò),如系統(tǒng)調(diào)用號(hào)非法 
  #define SIGUNUSED SIGSYS//不使用

  #define _NSIG 65

信號(hào)來(lái)源

信號(hào)來(lái)源分為硬件類(lèi)和軟件類(lèi):

硬件類(lèi)

用戶輸入:比如在終端上按下組合鍵ctrl+C,產(chǎn)生SIGINT信號(hào);

硬件異常:CPU檢測(cè)到內(nèi)存非法訪問(wèn)等異常,通知內(nèi)核生成相應(yīng)信號(hào),并發(fā)送給發(fā)生事件的進(jìn)程;

軟件類(lèi)

通過(guò)系統(tǒng)調(diào)用,發(fā)送signal信號(hào):kill(),raise(),sigqueue(),alarm(),setitimer(),abort()

kill命令就是一個(gè)發(fā)送信號(hào)的工具,用于向進(jìn)程或進(jìn)程組發(fā)送信號(hào).例如:kill 9 PID(SIGKILL)來(lái)殺死PID進(jìn)程.

sigqueue():只能向一個(gè)進(jìn)程發(fā)送信號(hào),不能向進(jìn)程組發(fā)送信號(hào);主要針對(duì)實(shí)時(shí)信號(hào)提出,與sigaction()組合使用,當(dāng)然也支持非實(shí)時(shí)信號(hào)的發(fā)送;

alarm():用于調(diào)用進(jìn)程指定時(shí)間后發(fā)出SIGALARM信號(hào);

setitimer():設(shè)置定時(shí)器,計(jì)時(shí)達(dá)到后給進(jìn)程發(fā)送SIGALRM信號(hào),功能比alarm更強(qiáng)大;

abort():向進(jìn)程發(fā)送SIGABORT信號(hào),默認(rèn)進(jìn)程會(huì)異常退出。

raise():用于向進(jìn)程自身發(fā)送信號(hào);

信號(hào)與進(jìn)程的關(guān)系

主要是通過(guò)系統(tǒng)調(diào)用sigaction將用戶態(tài)信號(hào)處理函數(shù)注冊(cè)到PCB保存.所有進(jìn)程的任務(wù)都共用這個(gè)信號(hào)注冊(cè)函數(shù)sigHandler,在信號(hào)的消費(fèi)階段內(nèi)核用一種特殊的方式'回調(diào)'它.

typedef struct ProcessCB {//PCB中關(guān)于信號(hào)的信息
    UINTPTR              sigHandler;   /**< signal handler */   //捕捉信號(hào)后的處理函數(shù)
    sigset_t             sigShare;     /**< signal share bit */	//信號(hào)共享位,64個(gè)信號(hào)各站一位
}LosProcessCB;
typedef unsigned _Int64 sigset_t; //一個(gè)64位的變量,每個(gè)信號(hào)代表一位.

struct sigaction {//信號(hào)處理機(jī)制結(jié)構(gòu)體
	union {
		void (*sa_handler)(int); //信號(hào)處理函數(shù)——普通版
		void (*sa_sigaction)(int, siginfo_t *, void *);//信號(hào)處理函數(shù)——高級(jí)版
	} __sa_handler;
	sigset_t sa_mask;//指定信號(hào)處理程序執(zhí)行過(guò)程中需要阻塞的信號(hào);
	int sa_flags;	 //標(biāo)示位
					 //	SA_RESTART:使被信號(hào)打斷的syscall重新發(fā)起。
					 //	SA_NOCLDSTOP:使父進(jìn)程在它的子進(jìn)程暫停或繼續(xù)運(yùn)行時(shí)不會(huì)收到 SIGCHLD 信號(hào)。
					 //	SA_NOCLDWAIT:使父進(jìn)程在它的子進(jìn)程退出時(shí)不會(huì)收到SIGCHLD信號(hào),這時(shí)子進(jìn)程如果退出也不會(huì)成為僵 尸進(jìn)程。
					 //	SA_NODEFER:使對(duì)信號(hào)的屏蔽無(wú)效,即在信號(hào)處理函數(shù)執(zhí)行期間仍能發(fā)出這個(gè)信號(hào)。
					 //	SA_RESETHAND:信號(hào)處理之后重新設(shè)置為默認(rèn)的處理方式。
					 //	SA_SIGINFO:使用sa_sigaction成員而不是sa_handler作為信號(hào)處理函數(shù)。
	void (*sa_restorer)(void);
};
typedef struct sigaction sigaction_t;

解讀

每個(gè)信號(hào)都對(duì)應(yīng)一個(gè)位. 信號(hào)從1開(kāi)始編號(hào) [1 ~ 64] 對(duì)應(yīng)sigShare的[0 ~ 63]位,所以中間會(huì)差一個(gè).記住這點(diǎn),后續(xù)代碼會(huì)提到.

sigHandler信號(hào)處理函數(shù)的注冊(cè)過(guò)程,由系統(tǒng)調(diào)用sigaction(用戶空間) ->OsSigAction(內(nèi)核空間)完成綁定動(dòng)作.

#include 
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;
    }
    //將數(shù)據(jù)從用戶空間拷貝到內(nèi)核空間
    if (LOS_ArchCopyFromUser(&action, act, sizeof(sigaction_t)) != LOS_OK) {
        return -EFAULT;
    }

    if (sig == SIGSYS) {//鴻蒙此處通過(guò)錯(cuò)誤的系統(tǒng)調(diào)用 來(lái)安裝信號(hào)處理函數(shù),有點(diǎn)巧妙. 
        addr = OsGetSigHandler();//獲取進(jìn)程信號(hào)處理函數(shù)
        if (addr == 0) {//進(jìn)程沒(méi)有設(shè)置信號(hào)處理函數(shù)時(shí)
            OsSetSigHandler((unsigned long)(UINTPTR)action.sa_handler);//設(shè)置進(jìn)程信號(hào)處理函數(shù)——普通版
            return LOS_OK;
        }
        return -EINVAL;
    }

    return LOS_OK;
}

sigaction(...)第一個(gè)參數(shù)是要安裝的信號(hào); 第二個(gè)參數(shù)與sigaction函數(shù)同名的結(jié)構(gòu)體,這里會(huì)讓人很懵,函數(shù)名和結(jié)構(gòu)體一直,沒(méi)明白為毛要這么搞? 結(jié)構(gòu)體內(nèi)定義了信號(hào)處理方法;第三個(gè)為輸出參數(shù),將信號(hào)的當(dāng)前的sigaction結(jié)構(gòu)帶回.但鴻蒙顯然沒(méi)有認(rèn)真對(duì)待第三個(gè)參數(shù).把musl實(shí)現(xiàn)給閹割了.

對(duì)結(jié)構(gòu)體的sigaction鴻蒙目前只支持信號(hào)處理函數(shù)——普通版,sa_handler表示自定義信號(hào)處理函數(shù),該函數(shù)返回值為void,可以帶一個(gè)int參數(shù),通過(guò)參數(shù)可以得知當(dāng)前信號(hào)的編號(hào),這樣就可以用同一個(gè)函數(shù)處理多種信號(hào)。

sa_mask指定信號(hào)處理程序執(zhí)行過(guò)程中需要阻塞的信號(hào)。

sa_flags字段包含一些選項(xiàng),具體看注釋

sa_sigaction是實(shí)時(shí)信號(hào)的處理函數(shù),union二選一.鴻蒙暫時(shí)不支持這種方式.

信號(hào)與任務(wù)的關(guān)系

typedef struct {//TCB中關(guān)于信號(hào)的信息
    sig_cb          sig;	//信號(hào)控制塊,用于異步通信,類(lèi)似于 linux singal模塊
} LosTaskCB;
typedef struct {//信號(hào)控制塊(描述符)
    sigset_t sigFlag;		//不屏蔽的信號(hào)標(biāo)簽集
    sigset_t sigPendFlag;	//信號(hào)阻塞標(biāo)簽集,記錄因哪些信號(hào)被阻塞
    sigset_t sigprocmask; /* Signals that are blocked            */	//進(jìn)程屏蔽了哪些信號(hào)
    sq_queue_t sigactionq;	//信號(hào)捕捉隊(duì)列					
    LOS_DL_LIST waitList;	//等待鏈表,上面掛的是等待信號(hào)到來(lái)的任務(wù), 可查找 OsTaskWait(&sigcb->waitList, timeout, TRUE)	理解						
    sigset_t sigwaitmask; /* Waiting for pending signals         */	//任務(wù)在等待阻塞信號(hào)
    siginfo_t sigunbinfo; /* Signal info when task unblocked     */	//任務(wù)解鎖時(shí)的信號(hào)信息
    sig_switch_context context;	//信號(hào)切換上下文, 用于保存切換現(xiàn)場(chǎng), 比如發(fā)生系統(tǒng)調(diào)用時(shí)的返回,涉及同一個(gè)任務(wù)的兩個(gè)棧進(jìn)行切換							
} sig_cb;

解讀

系列篇已多次說(shuō)過(guò),進(jìn)程只是管理資源的容器,真正讓cpu干活的是任務(wù)task,所以發(fā)給進(jìn)程的信號(hào)最終還是需要分發(fā)給具體任務(wù)來(lái)處理.所以能想到的是關(guān)于任務(wù)部分會(huì)更復(fù)雜.

context信號(hào)處理很復(fù)雜的原因在于信號(hào)的發(fā)起在用戶空間,發(fā)送需要系統(tǒng)調(diào)用,而處理信號(hào)的函數(shù)又是用戶空間提供的, 所以需要反復(fù)的切換任務(wù)上下文.而且還有硬中斷的問(wèn)題,比如 ctrl + c ,需要從硬中斷中回調(diào)用戶空間的信號(hào)處理函數(shù),處理完了再回到內(nèi)核空間,最后回到用戶空間.沒(méi)聽(tīng)懂吧,我自己都說(shuō)暈了,所以需要專(zhuān)門(mén)的一篇來(lái)說(shuō)清楚信號(hào)的處理問(wèn)題.本篇不展開(kāi)說(shuō).

sig_cb結(jié)構(gòu)體是任務(wù)處理信號(hào)的結(jié)構(gòu)體,要響應(yīng),屏蔽哪些信號(hào)等等都由它完成,這個(gè)結(jié)構(gòu)體雖不復(fù)雜,但是很繞,很難搞清楚它們之間的區(qū)別.筆者是經(jīng)過(guò)一番痛苦的閱讀理解后才明白各自的含義.并想通過(guò)用打比方的例子試圖讓大家明白.

以下用追女孩打比方理解.任務(wù)相當(dāng)于某個(gè)男,沒(méi)錯(cuò)說(shuō)的就是屏幕前的你,除了苦逼的碼農(nóng)誰(shuí)會(huì)有耐心能堅(jiān)持看到這里.64個(gè)信號(hào)對(duì)應(yīng)64個(gè)女孩.允許一男同時(shí)追多個(gè)女孩,女孩也可同時(shí)被多個(gè)男追.女孩也可以主動(dòng)追男的.理解如下:

waitList等待信號(hào)的任務(wù)鏈表,上面掛的是因等待信號(hào)而被阻塞的任務(wù).眾男在排隊(duì)追各自心愛(ài)的女孩們,處于無(wú)所事事的掛起的狀態(tài),等待女孩們的出現(xiàn).

sigwaitmask任務(wù)在等待的信號(hào)集合,只有這些信號(hào)能喚醒任務(wù).相當(dāng)于列出喜歡的各位女孩,只要出現(xiàn)一位就能讓你滿血復(fù)活.

sigprocmask指任務(wù)對(duì)哪些信號(hào)不感冒.來(lái)了也不處理.相當(dāng)于列出不喜歡的各位女孩,請(qǐng)她們別來(lái)騷擾你,嘚瑟.

sigPendFlag信號(hào)到達(dá)但并未喚醒任務(wù).相當(dāng)于喜歡你的女孩來(lái)追你,但她不在你喜歡的列表內(nèi),結(jié)果是不搭理人家繼續(xù)等喜歡的出現(xiàn).

sigFlag記錄不屏蔽的信號(hào)集合,相當(dāng)于你并不反感的女孩們.記錄來(lái)過(guò)的那些女孩(除掉你不喜歡的).

信號(hào)發(fā)送過(guò)程

用戶進(jìn)程調(diào)用kill()的過(guò)程如下:

kill(pid_t pid, int sig) - 系統(tǒng)調(diào)用   
|                    用戶空間
---------------------------------------------------------------------------------------
|                    內(nèi)核空間
SysKill(...)
|---> OsKillLock(...)
    |---> OsKill(.., OS_USER_KILL_PERMISSION)
        |---> OsDispatch()  //鑒權(quán),向進(jìn)程發(fā)送信號(hào)
            |---> OsSigProcessSend()    //選擇任務(wù)發(fā)送信號(hào)
                |---> OsSigProcessForeachChild(..,ForEachTaskCB handler,..)
                    |---> SigProcessKillSigHandler() //處理 SIGKILL
                        |---> OsTaskWake() //喚醒所有等待任務(wù)
                        |---> OsSigEmptySet() //清空信號(hào)等待集
                    |---> SigProcessSignalHandler()
                        |---> OsTcbDispatch() //向目標(biāo)任務(wù)發(fā)送信號(hào)
                            |---> OsTaskWake() //喚醒任務(wù)
                            |---> OsSigEmptySet() //清空信號(hào)等待集

流程

通過(guò) 系統(tǒng)調(diào)用kill陷入內(nèi)核空間

因?yàn)槭怯脩魬B(tài)進(jìn)程,使用OS_USER_KILL_PERMISSION權(quán)限發(fā)送信號(hào)

#define OS_KERNEL_KILL_PERMISSION 0U	//內(nèi)核態(tài) kill 權(quán)限
#define OS_USER_KILL_PERMISSION   3U	//用戶態(tài) kill 權(quán)限

鑒權(quán)之后進(jìn)程輪詢?nèi)蝿?wù)組,向目標(biāo)任務(wù)發(fā)送信號(hào).這里分三種情況:

SIGKILL信號(hào),將所有等待任務(wù)喚醒,拉入就緒隊(duì)列等待被調(diào)度執(zhí)行,并情況信號(hào)等待集

非SIGKILL信號(hào)時(shí),將通過(guò)sigwaitmask和sigprocmask過(guò)濾,找到一個(gè)任務(wù)向它發(fā)送信號(hào)OsTcbDispatch.

代碼細(xì)節(jié)

    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) {//有效信號(hào) [0,64]
            return -EINVAL;
        }
        if (OsProcessIDUserCheckInvalid(pid)) {//檢查參數(shù)進(jìn)程 
            return -ESRCH;
        }

        /* Create the siginfo structure */ //創(chuàng)建信號(hào)結(jié)構(gòu)體
        info.si_signo = sig;	//信號(hào)編號(hào)
        info.si_code = SI_USER;	//來(lái)自用戶進(jìn)程信號(hào)
        info.si_value.sival_ptr = NULL;

        /* Send the signal */
        ret = OsDispatch(pid, &info, permission);//發(fā)送信號(hào)
        return ret;
    }

    //信號(hào)分發(fā)
    int OsDispatch(pid_t pid, siginfo_t *info, int permission)
    {
        LosProcessCB *spcb = OS_PCB_FROM_PID(pid);//找到這個(gè)進(jìn)程
        if (OsProcessIsUnused(spcb)) {//進(jìn)程是否還在使用,不一定是當(dāng)前進(jìn)程但必須是個(gè)有效進(jìn)程
            return -ESRCH;
        }
    #ifdef LOSCFG_SECURITY_CAPABILITY	//啟用能力安全模式
        LosProcessCB *current = OsCurrProcessGet();//獲取當(dāng)前進(jìn)程

        /* If the process you want to kill had been inactive, but still exist. should return LOS_OK */
        if (OsProcessIsInactive(spcb)) {//如果要終止的進(jìn)程處于非活動(dòng)狀態(tài),但仍然存在,應(yīng)該返回OK
            return LOS_OK;
        }

        /* Kernel process always has kill permission and user process should check permission *///內(nèi)核進(jìn)程總是有kill權(quán)限,用戶進(jìn)程需要檢查權(quán)限
        if (OsProcessIsUserMode(current) && !(current->processStatus & OS_PROCESS_FLAG_EXIT)) {//用戶進(jìn)程檢查能力范圍
            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);//給參數(shù)進(jìn)程發(fā)送信號(hào)
    }

    //給參數(shù)進(jìn)程發(fā)送參數(shù)信號(hào)
    int OsSigProcessSend(LosProcessCB *spcb, siginfo_t *sigInfo)
    {
        int ret;
        struct ProcessSignalInfo info = {
            .sigInfo = sigInfo, //信號(hào)內(nèi)容
            .defaultTcb = NULL, //以下四個(gè)值將在OsSigProcessForeachChild中根據(jù)條件完善
            .unblockedTcb = NULL,
            .awakenedTcb = NULL,
            .receivedTcb = NULL
        };
        //總之是要從進(jìn)程中找個(gè)至少一個(gè)任務(wù)來(lái)接受這個(gè)信號(hào),優(yōu)先級(jí)
        //awakenedTcb > receivedTcb > unblockedTcb > defaultTcb
        /* visit all taskcb and dispatch signal */ //訪問(wèn)所有任務(wù)和分發(fā)信號(hào)
        if ((info.sigInfo != NULL) && (info.sigInfo->si_signo == SIGKILL)) {//需要干掉進(jìn)程時(shí) SIGKILL = 9, #linux kill 9 14
            (void)OsSigProcessForeachChild(spcb, SigProcessKillSigHandler, &info);//進(jìn)程要被干掉了,通知所有task做善后處理
            OsSigAddSet(&spcb->sigShare, info.sigInfo->si_signo);
            OsWaitSignalToWakeProcess(spcb);//等待信號(hào)喚醒進(jìn)程
            return 0;
        } else {
            ret = OsSigProcessForeachChild(spcb, SigProcessSignalHandler, &info);//進(jìn)程通知所有task處理信號(hào)
        }
        if (ret < 0) {
            return ret;
        }
        SigProcessLoadTcb(&info, sigInfo);
        return 0;
    }
    //讓進(jìn)程的每一個(gè)task執(zhí)行參數(shù)函數(shù)
    int OsSigProcessForeachChild(LosProcessCB *spcb, ForEachTaskCB handler, void *arg)
    {
        int ret;

        /* Visit the main thread last (if present) */	
        LosTaskCB *taskCB = NULL;//遍歷進(jìn)程的 threadList 鏈表,里面存放的都是task節(jié)點(diǎn)
        LOS_DL_LIST_FOR_EACH_ENTRY(taskCB, &(spcb->threadSiblingList), LosTaskCB, threadList) {//遍歷進(jìn)程的任務(wù)列表
            ret = handler(taskCB, arg);//回調(diào)參數(shù)函數(shù)
            OS_RETURN_IF(ret != 0, ret);//這個(gè)宏的意思就是只有ret = 0時(shí),啥也不處理.其余就返回 ret
        }
        return LOS_OK;
    }

如果是SIGKILL信號(hào),讓spcb的所有任務(wù)執(zhí)行SigProcessKillSigHandler函數(shù),查看旗下的所有任務(wù)是否又在等待這個(gè)信號(hào)的,如果有就將任務(wù)喚醒,放在就緒隊(duì)列等待被調(diào)度執(zhí)行.

//進(jìn)程收到 SIGKILL 信號(hào)后,通知任務(wù)tcb處理.
static int SigProcessKillSigHandler(LosTaskCB *tcb, void *arg)
{
    struct ProcessSignalInfo *info = (struct ProcessSignalInfo *)arg;//轉(zhuǎn)參

    if ((tcb != NULL) && (info != NULL) && (info->sigInfo != NULL)) {//進(jìn)程有信號(hào)
        sig_cb *sigcb = &tcb->sig;
        if (!LOS_ListEmpty(&sigcb->waitList) && OsSigIsMember(&sigcb->sigwaitmask, info->sigInfo->si_signo)) {//如果任務(wù)在等待這個(gè)信號(hào)
            OsTaskWake(tcb);//喚醒這個(gè)任務(wù),加入進(jìn)程的就緒隊(duì)列,并不申請(qǐng)調(diào)度
            OsSigEmptySet(&sigcb->sigwaitmask);//清空信號(hào)等待位,不等任何信號(hào)了.因?yàn)檫@是SIGKILL信號(hào)
        }
    }
    return 0;
}

非SIGKILL信號(hào),讓spcb的所有任務(wù)執(zhí)行SigProcessSignalHandler函數(shù)

static int SigProcessSignalHandler(LosTaskCB *tcb, void *arg)
{
    struct ProcessSignalInfo *info = (struct ProcessSignalInfo *)arg;//先把參數(shù)解出來(lái)
    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) {//如果沒(méi)有默認(rèn)發(fā)送方的任務(wù),即默認(rèn)參數(shù)任務(wù).
        info->defaultTcb = tcb;
    }

    isMember = OsSigIsMember(&tcb->sig.sigwaitmask, info->sigInfo->si_signo);//任務(wù)是否在等待這個(gè)信號(hào)
    if (isMember && (!info->awakenedTcb)) {//是在等待,并尚未向該任務(wù)時(shí)發(fā)送信號(hào)時(shí)
        /* 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);//發(fā)送信號(hào),注意這是給其他任務(wù)發(fā)送信號(hào),tcb不是當(dāng)前任務(wù)
        OS_RETURN_IF(ret < 0, ret);//這種寫(xiě)法很有意思

        /* 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);//任務(wù)是否屏蔽了這個(gè)信號(hào)
    if ((!isMember) && (!info->receivedTcb) && (tcb != info->awakenedTcb)) {//沒(méi)有屏蔽,有喚醒任務(wù)沒(méi)有接收任務(wù).
        /* if unblockedTcb of this signal is not setted, then set it. */
        if (!info->unblockedTcb) {
            info->unblockedTcb = tcb;
        }

        ret = OsTcbDispatch(tcb, info->sigInfo);//向任務(wù)發(fā)送信號(hào)
        OS_RETURN_IF(ret < 0, ret);
        /* set this tcb as receivedTcb */
        info->receivedTcb = tcb;//設(shè)置這個(gè)任務(wù)為接收任務(wù)
        OS_RETURN_IF(info->awakenedTcb != NULL, SIG_STOP_VISIT); /* Stop search */
    }
    return 0; /* Keep searching */
}
解讀

函數(shù)的意思是,當(dāng)進(jìn)程中有多個(gè)任務(wù)在等待這個(gè)信號(hào)時(shí),發(fā)送信號(hào)給第一個(gè)等待的任務(wù)awakenedTcb.

如果沒(méi)有任務(wù)在等待信號(hào),那就從不屏蔽這個(gè)信號(hào)的任務(wù)集中隨機(jī)找一個(gè)receivedTcb接受信號(hào).

只要不屏蔽unblockedTcb就有值,隨機(jī)的.

如果上面的都不滿足,信號(hào)發(fā)送給defaultTcb.

尋找發(fā)送任務(wù)的優(yōu)先級(jí)是awakenedTcb>receivedTcb>unblockedTcb>defaultTcb

信號(hào)相關(guān)函數(shù)

信號(hào)集操作函數(shù)

sigemptyset(sigset_t *set):信號(hào)集全部清0;

sigfillset(sigset_t *set): 信號(hào)集全部置1,則信號(hào)集包含linux支持的64種信號(hào);

sigaddset(sigset_t *set, int signum):向信號(hào)集中加入signum信號(hào);

sigdelset(sigset_t *set, int signum):向信號(hào)集中刪除signum信號(hào);

sigismember(const sigset_t *set, int signum):判定信號(hào)signum是否存在信號(hào)集中。

信號(hào)阻塞函數(shù)

sigprocmask(int how, const sigset_t *set, sigset_t *oldset)); 不同how參數(shù),實(shí)現(xiàn)不同功能

SIG_BLOCK:將set指向信號(hào)集中的信號(hào),添加到進(jìn)程阻塞信號(hào)集;

SIG_UNBLOCK:將set指向信號(hào)集中的信號(hào),從進(jìn)程阻塞信號(hào)集刪除;

SIG_SETMASK:將set指向信號(hào)集中的信號(hào),設(shè)置成進(jìn)程阻塞信號(hào)集;

sigpending(sigset_t *set)):獲取已發(fā)送到進(jìn)程,卻被阻塞的所有信號(hào);

sigsuspend(const sigset_t *mask)):用mask代替進(jìn)程的原有掩碼,并暫停進(jìn)程執(zhí)行,直到收到信號(hào)再恢復(fù)原有掩碼并繼續(xù)執(zhí)行進(jìn)程。

編輯:hfy

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • cpu
    cpu
    +關(guān)注

    關(guān)注

    68

    文章

    10827

    瀏覽量

    211174
  • 實(shí)時(shí)信號(hào)

    關(guān)注

    0

    文章

    4

    瀏覽量

    5187
  • 鴻蒙系統(tǒng)
    +關(guān)注

    關(guān)注

    183

    文章

    2634

    瀏覽量

    66221
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    鴻蒙內(nèi)核源碼Task/線程技術(shù)分析

    前言 在鴻蒙內(nèi)核中,廣義上可理解為一個(gè)Task就是一個(gè)線程 一、怎么理解Task 1. 官方文檔是怎么描述線程 基本概念 從系統(tǒng)的角度看,線程是競(jìng)爭(zhēng)系統(tǒng)資源的最小運(yùn)行單元。線程可以使用或等待CPU
    的頭像 發(fā)表于 10-18 10:42 ?2180次閱讀
    <b class='flag-5'>鴻蒙</b><b class='flag-5'>內(nèi)核</b><b class='flag-5'>源碼</b>Task/線程技術(shù)<b class='flag-5'>分析</b>

    鴻蒙內(nèi)核源碼分析:用通俗易懂的語(yǔ)言告訴你鴻蒙內(nèi)核發(fā)生了什么?

    查看。內(nèi)存在內(nèi)核的比重極大內(nèi)存模塊占了鴻蒙內(nèi)核約15%代碼量, 近50個(gè)文件,非常復(fù)雜。鴻蒙源碼分析
    發(fā)表于 11-19 10:14

    鴻蒙內(nèi)核源碼分析源碼注釋篇):給HarmonyOS源碼逐行加上中文注釋

    都懂的概念去詮釋或者映射一個(gè)他們從沒(méi)聽(tīng)過(guò)的概念.說(shuō)別人能聽(tīng)得懂的話這很重要!!! 一個(gè)沒(méi)學(xué)過(guò)計(jì)算機(jī)知識(shí)的賣(mài)菜大媽就不可能知道內(nèi)核的基本運(yùn)作了嗎? NO!,筆者在系列篇中試圖用 鴻蒙源碼分析
    發(fā)表于 11-19 10:32

    鴻蒙內(nèi)核源碼分析:給HarmonyOS源碼逐行加上中文注釋

    過(guò)計(jì)算機(jī)知識(shí)的賣(mài)菜大媽就不可能知道內(nèi)核的基本運(yùn)作了嗎? NO!,筆者在系列篇中試圖用 鴻蒙源碼分析系列篇|張大爺系列故事【 CSDN | OSCHINA】 去構(gòu)建這一層級(jí)的認(rèn)知,希望能
    發(fā)表于 11-19 15:06

    鴻蒙源碼分析系列(總目錄) | 給HarmonyOS源碼逐行加上中文注釋

    同步更新。鴻蒙源碼分析系列篇|- 鴻蒙內(nèi)核源碼分析
    發(fā)表于 11-20 11:24

    鴻蒙內(nèi)核源碼分析(內(nèi)存概念篇) :手眼通天的虛擬內(nèi)存

    內(nèi)存模塊占了 HarmonyOS 內(nèi)核約15%代碼量, 近20個(gè).c文件,很復(fù)雜。系列篇將用九篇來(lái)介紹HarmonyOS內(nèi)存部分,分別是 鴻蒙內(nèi)核源碼
    發(fā)表于 11-20 16:30

    鴻蒙內(nèi)核源碼分析(必讀篇):用故事說(shuō)內(nèi)核

    本文基于開(kāi)源鴻蒙內(nèi)核分析,官方源碼【kernel_liteos_a】官方文檔【docs】參考文檔【Huawei LiteOS】本文作者:鴻蒙
    發(fā)表于 11-23 10:15

    鴻蒙內(nèi)核源碼分析(必讀篇)

    本文基于開(kāi)源鴻蒙內(nèi)核分析,官方源碼【kernel_liteos_a】官方文檔【docs】參考文檔【Huawei LiteOS】本文作者:鴻蒙
    發(fā)表于 11-25 09:28

    HarmonyOS內(nèi)核源碼分析(上)電子書(shū)-上線了

    `為方便大家開(kāi)發(fā)鴻蒙系統(tǒng),小編為大家編輯整理了一本HarmonyOS內(nèi)核源碼分析系列電子書(shū),需要參考學(xué)習(xí)的朋友快來(lái)下吧!本電子書(shū)主要介紹如何給鴻蒙
    發(fā)表于 11-25 17:13

    鴻蒙內(nèi)核源碼分析(百篇博客分析.挖透鴻蒙內(nèi)核)

    致敬內(nèi)核開(kāi)發(fā)者感謝開(kāi)放原子開(kāi)源基金會(huì),致敬鴻蒙內(nèi)核開(kāi)發(fā)者。可以毫不夸張的說(shuō)鴻蒙內(nèi)核源碼可作為大學(xué)
    發(fā)表于 07-04 17:16

    為何要精讀鴻蒙內(nèi)核源碼?

    一個(gè)沒(méi)學(xué)過(guò)計(jì)算機(jī)知識(shí)的賣(mài)菜大媽就不可能知道內(nèi)核的基本運(yùn)作了嗎? 不一定!在系列篇中試圖用 鴻蒙內(nèi)核源碼分析(總目錄)之故事篇 去引導(dǎo)這一層級(jí)
    的頭像 發(fā)表于 04-26 15:00 ?1850次閱讀
    為何要精讀<b class='flag-5'>鴻蒙</b><b class='flag-5'>內(nèi)核</b><b class='flag-5'>源碼</b>?

    鴻蒙內(nèi)核源碼分析鴻蒙內(nèi)核的每段匯編代碼解析

    本篇說(shuō)清楚CPU的工作模式 讀本篇之前建議先讀鴻蒙內(nèi)核源碼分析(總目錄)其他篇. 正如一個(gè)互聯(lián)網(wǎng)項(xiàng)目的后臺(tái)管理系統(tǒng)有權(quán)限管理一樣,CPU工作是否也有權(quán)限(模式)? 一個(gè)成熟的軟硬件架構(gòu)
    的頭像 發(fā)表于 03-02 09:56 ?4303次閱讀
    <b class='flag-5'>鴻蒙</b><b class='flag-5'>內(nèi)核</b><b class='flag-5'>源碼</b><b class='flag-5'>分析</b>:<b class='flag-5'>鴻蒙</b><b class='flag-5'>內(nèi)核</b>的每段匯編代碼解析

    鴻蒙內(nèi)核源碼分析: 虛擬內(nèi)存和物理內(nèi)存是怎么管理的

    有了上篇鴻蒙內(nèi)核源碼分析(內(nèi)存概念篇)的基礎(chǔ),本篇講內(nèi)存管理部分,本章源碼超級(jí)多,很燒腦,但筆者關(guān)鍵處都加了注釋。廢話不多說(shuō),開(kāi)始吧。內(nèi)存一
    發(fā)表于 11-23 11:45 ?19次下載
    <b class='flag-5'>鴻蒙</b><b class='flag-5'>內(nèi)核</b><b class='flag-5'>源碼</b><b class='flag-5'>分析</b>: 虛擬內(nèi)存和物理內(nèi)存是怎么管理的

    鴻蒙內(nèi)核源碼分析內(nèi)核最重要結(jié)構(gòu)體

    為何鴻蒙內(nèi)核源碼分析系列開(kāi)篇就說(shuō) LOS_DL_LIST ? 因?yàn)樗?b class='flag-5'>鴻蒙 LOS 內(nèi)核中無(wú)處
    發(fā)表于 11-24 17:54 ?35次下載
    <b class='flag-5'>鴻蒙</b><b class='flag-5'>內(nèi)核</b><b class='flag-5'>源碼</b><b class='flag-5'>分析</b> :<b class='flag-5'>內(nèi)核</b>最重要結(jié)構(gòu)體

    華為鴻蒙系統(tǒng)內(nèi)核源碼分析上冊(cè)

    鴻蒙內(nèi)核源碼注釋中文版【 Gitee倉(cāng)】給 Harmoηy○S源碼逐行加上中文注解,詳細(xì)闡述設(shè)計(jì)細(xì)節(jié),助你快速精讀 Harmonyos內(nèi)核源碼
    發(fā)表于 04-09 14:40 ?17次下載