成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

OS內核的信號機制:所有的異步都可以是同步的

系統(tǒng) 其他OS
每個進程,在OS內核里都被一個task結構體表示,這個結構體的其中一個成員變量就是記錄信號的:我們給他起名叫sigmap,Linux的不一定要叫這個名字,但肯定有這一項。

今天條友@xiamenuser給我提了一個關于操作系統(tǒng)的問題:怎么把定時器線程里的回調函數(shù),(在定時器觸發(fā)之后)挪到工作線程里運行?

這個需求要做的事,跟Linux內核的信號機制是一樣的。

OS內核的信號機制,在1970年的Unix時代就有了,是一個上古話題。

在unix里,可以使用kill -9 pid命令殺掉進程(pid為進程號),在Linux里也可以。

1.OS內核的信號

有個專有的宏定義#define SIGKILL 9,然后信號9就成了一個特別牛的信號,大概除了0號idle進程和1號init進程之外,其他進程都可以殺死。

0號進程和1號進程是不能殺死的,否則系統(tǒng)就崩潰了!

int sys_kill(int sig, int pid)
{
if (sig < 0 || pid < 0)
return -EINVAL;
if (0 == pid || 1 == pid) {
if (SIGKILL == sig) return -1;
}
tasks[pid]->sigmap |= 1 << sig;
return 0;
}

OS內核里對應著kill命令的sys_kill()系統(tǒng)調用,大概是上面這樣:

在進程的task結構體的sigmap成員變量上,設置1個標志位,進程就可以收到信號了。

每個進程,在OS內核里都被一個task結構體表示,這個結構體的其中一個成員變量就是記錄信號的:我們給他起名叫sigmap,Linux的不一定要叫這個名字,但肯定有這一項。

這個信號在什么時候處理呢?

等到收信號的進程下一次被調度運行的時候。

當前運行的進程,肯定是發(fā)信號的進程,否則它沒法主動發(fā)起kill()系統(tǒng)調用。

發(fā)信號的進程做的事,只是把信號設置到接收進程的信號圖上,這時信號實際上已經(jīng)發(fā)到了:但是接收進程并不會馬上因為SIGKILL信號而被殺死。

SIGKILL信號的殺進程,實際上進程是自殺的!

當收到信號的進程再次被調度運行的時候,操作系統(tǒng)會讓它先執(zhí)行信號的處理函數(shù),而SIGKILL的處理函數(shù),就是exit()系統(tǒng)調用:進程退出。

這個過程可以是異步的,等到接收進程下一次被調度時再處理,至于什么時候輪到它:等吧。

也可以讓它馬上同步處理,只需要在sys_kill()函數(shù)的末尾加一行代碼就行:

shedule_task( tasks[pid] );

直接選擇接收進程是下一個要調度的進程,并且馬上調度它運行:接下來它就完事了。

不需要等OS內核統(tǒng)計時間片,確定調度的優(yōu)先級了,既然用戶想讓它掛掉,OS當然要馬上讓它掛掉。

畢竟Linux系統(tǒng)也惹不起用戶啊,用戶是可以重裝windows的?

接下來,說說shedule_task()之后的細節(jié)。

2.信號是怎么處理的

每個信號都有一個處理函數(shù),叫信號處理函數(shù)。

信號處理函數(shù),是在用戶態(tài)的代碼里運行的。

所以,程序員可以自己給部分信號編寫處理函數(shù),用signal()系統(tǒng)調用注冊到OS內核,就可以(在收到信號時)運行這個自己編寫的函數(shù)了。

如果信號處理函數(shù)是在內核狀態(tài)運行的,那顯然用戶編寫的函數(shù)是沒法運行的,因為用戶函數(shù)的內存地址在用戶空間(它在進程的代碼段里)。

OS內核在信號處理時要做的是,把進程從內核返回后要運行的代碼地址,改成信號處理函數(shù)的地址。

修改過程如下:

系統(tǒng)內核的信號處理過程

1)進程從內核返回時的狀態(tài),如上圖。

內核棧上的寄存器排布順序不一定是對的,這要查intel的手冊,但是這些項肯定都有。

在進程使用iret指令(中斷返回)從內核返回的那一刻,內核棧上的這些數(shù)據(jù)都要彈出到對應的寄存器。

然后,進程就會運行EIP指向的用戶代碼,同時用戶態(tài)的棧頂就是ESP。

EIP和ESP指向的內容到底是什么,內核不需要管:這是由程序員寫代碼時確定的。

進程從內核返回之后的錯誤,錯的是程序員,不是系統(tǒng)內核。

但要是返不回來,或者不能處理信號,錯的就是系統(tǒng)內核了。

2)OS內核要做的是,修改內核棧上、保存的、用戶態(tài)的、EIP和ESP(注意這3個定語):

A,讓EIP指向信號處理函數(shù),

B,讓ESP指向信號處理函數(shù)的參數(shù),

C,在信號處理函數(shù)的下方,放上“真正的”返回地址,

D,在信號處理函數(shù)運行完之后,丟掉(信號處理函數(shù)的)參數(shù),彈出真正的返回地址:讓程序恢復正常的狀態(tài),繼續(xù)運行。

如上圖中的綠字部分。

如果一次要處理多個信號的話,就順著用戶棧繼續(xù)疊加就行。

siska內核demo里的信號處理代碼,如下的3張圖:

因為信號處理函數(shù)有參數(shù),而參數(shù)要壓在用戶態(tài)的棧上,所以信號處理函數(shù)運行完之后還要清理它。

所以,與一般的C函數(shù)不同,信號處理函數(shù)是被調函數(shù)清理堆棧的:即它是pascal調用,而不是C調用!

C調用,都是主調函數(shù)清理堆棧的。

所以,信號處理函數(shù)的總入口是一段匯編代碼,用來在C語言里完成這個pascal調用。

這么看來,pascal這種老語言,也不是想象的那么差?

這個信號處理方式,是我給出來的解決方案?

至于Linux是不是也這么做的,我就不知道了。

但是,這么做是可行的。

siska信號處理,pascal調用的匯編

上圖95行的call *(%eax),就是調用信號處理的函數(shù)指針。

它前后的匯編代碼,都是準備參數(shù)和清理堆棧。

3.回到開頭的問題

怎么讓定時器線程在觸發(fā)之后,讓回調函數(shù)在工作線程里運行?

回調函數(shù)一般有一個參數(shù),表示回調上下文,但沒有返回值。

因為定時器的添加和處理在2個線程里,回調函數(shù)的返回值沒有意義。

如果回調函數(shù)的處理出錯了,就在上下文里設置錯誤碼作為提示。

所以,它的函數(shù)聲明是這樣的:void callback(void* ctx);

要讓它正常運行,必須把回調上下文的指針添加到工作線程的用戶棧上,同時讓工作線程的內核棧上保存的EIP指向回調函數(shù)。

這個處理方式,與OS內核的信號處理方式是一樣的。

信號處理函數(shù)的聲明:void sighandler(int sig); 也是一個參數(shù)、無返回值。

在定時器觸發(fā)之后,定時器線程可以發(fā)起一個系統(tǒng)調用,把這些信息給到內核,然后內核修改工作線程的數(shù)據(jù),讓定時器的回調處理“像個信號”一樣就可以了?

這個系統(tǒng)調用如果Linux沒有提供的話,就只能自己修改Linux內核代碼,或者給Linus大牛提個需求了(他有可能看不過來你的郵件)。

PS:

工作線程和定時器線程在同一個進程里,所以它們的用戶態(tài)內存的代碼段、數(shù)據(jù)段、堆都是共享的,只是內核棧和用戶棧不一樣。

內核棧:在內核看來,每個線程也是一個可調度的進程,它必須有自己的內核棧和頁表。

同一個進程的不同線程之間共享內存,靠的是頁表的映射:把它們映射到同一個物理內存頁上。

用戶棧:不同的線程可以并發(fā)運行,它們的用戶棧肯定是不同的,否則局部變量就互相覆蓋了:這肯定是不可能的。

siska里信號處理的代碼,如下:

siska信號處理,1

siska信號處理,2

責任編輯:武曉燕 來源: 今日頭條
相關推薦

2023-04-03 09:44:18

2025-02-03 07:00:00

2011-07-05 18:40:19

QT 信號 機制

2011-07-05 18:32:52

QT 信號 機制

2024-07-16 10:52:09

2009-07-21 09:31:00

Scala操作符

2025-04-29 06:53:36

2021-12-10 00:01:53

Vsync信號機制

2017-05-15 11:39:36

2018-02-25 09:00:00

LinuxQ4OS開源

2011-10-11 16:57:13

windows8TechEd 2011

2022-03-31 08:15:59

遞歸代碼非遞歸

2022-03-11 11:40:26

AI數(shù)據(jù)技術

2009-11-12 09:51:11

Visual C++項

2014-09-24 13:04:13

微信企業(yè)號

2017-09-14 09:40:32

PythonUbuntu信號機制

2024-07-25 11:53:53

2013-07-04 09:46:06

X Phone

2011-06-17 14:36:50

Linux

2022-03-07 10:27:03

Linux開源社區(qū)
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产免费一区二区三区 | 亚洲视频免费观看 | 99re热精品视频国产免费 | 亚洲精品久久久久中文字幕二区 | 国产欧美精品一区二区 | 欧美日韩在线精品 | 狠狠亚洲 | 成人在线激情 | 日本一级淫片免费啪啪3 | 日韩精品在线视频免费观看 | 日韩三片 | 欧美一级片在线看 | 亚洲综合二区 | 麻豆va| 在线观看国产精品视频 | 国产精品美女久久久久久免费 | 亚洲在线电影 | 国产线视频精品免费观看视频 | 日韩成人精品一区 | 久久精品视频播放 | 精品国产久 | 97国产精品视频人人做人人爱 | 成人免费片 | 久久久久国产精品 | 国产精品视频免费播放 | 欧美日日日日bbbbb视频 | 2019中文字幕视频 | 91热爆在线观看 | 日韩欧美一区二区三区 | 国产激情偷乱视频一区二区三区 | 欧美激情视频一区二区三区在线播放 | 欧美日韩精品影院 | 国产精品777一区二区 | 成人在线亚洲 | 国产成人午夜精品影院游乐网 | 精品久久久久久久久久久下田 | 综合久久综合久久 | 一区二区三区影院 | 日韩欧美三级在线 | 看av在线 | 在线免费观看黄a |