日B视频 亚洲,啪啪啪网站一区二区,91色情精品久久,日日噜狠狠色综合久,超碰人妻少妇97在线,999青青视频,亚洲一区二卡,让本一区二区视频,日韩网站推荐

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

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

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

為什么Ctrl-C會(huì)導(dǎo)致當(dāng)前運(yùn)行程序退出呢?

dyquk4xk2p3d ? 來(lái)源:ytcoode ? 2023-09-08 09:23 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

0x01 問(wèn)題演示

下面是用rust寫(xiě)的一段測(cè)試程序,邏輯非常簡(jiǎn)單,就是讀取用戶輸入,然后將其輸出。

c8b0d366-4dd7-11ee-a25d-92fbcf53809c.png

運(yùn)行這個(gè)程序,然后按Ctrl-C:

c8c6ff06-4dd7-11ee-a25d-92fbcf53809c.png

由上圖可見(jiàn),該程序沒(méi)有收到任何輸入,當(dāng)然也沒(méi)有任何輸出,這個(gè)程序就退出了。

為什么Ctrl-C會(huì)導(dǎo)致當(dāng)前運(yùn)行程序退出呢?

0x02 程序退出原因

上面的測(cè)試程序之所以會(huì)退出,是因?yàn)镃trl-C會(huì)告訴linux內(nèi)核,讓其發(fā)送SIGINT信號(hào)給當(dāng)前運(yùn)行程序,該信號(hào)的默認(rèn)行為是殺掉目標(biāo)進(jìn)程,所以就有了上面的現(xiàn)象。

但是,SIGINT信號(hào),以及其他的各種信號(hào),都是可以捕獲的,這樣我們就可以修改信號(hào)的默認(rèn)行為,比如將SIGINT信號(hào)的默認(rèn)行為,修改成輸出一些日志,而不是殺掉當(dāng)前進(jìn)程。

將上面的測(cè)試代碼改成下面的樣子:

c8ddab8e-4dd7-11ee-a25d-92fbcf53809c.png

上圖中我們捕獲了SIGINT信號(hào),并且在收到該信號(hào)后,輸出 got SIGINT。

運(yùn)行看下:

c8f71c68-4dd7-11ee-a25d-92fbcf53809c.png

這次再按Ctrl-C,程序就不會(huì)退出了,而且還會(huì)輸出 got SIGINT。

由上可見(jiàn),Ctrl-C導(dǎo)致程序退出,確實(shí)是因?yàn)樵摪存I使內(nèi)核發(fā)送了SIGINT信號(hào)到目標(biāo)進(jìn)程,進(jìn)而導(dǎo)致目標(biāo)進(jìn)程被殺死。

那為什么Ctrl-C會(huì)觸發(fā)SIGINT信號(hào)呢?

在回答這個(gè)問(wèn)題之前,我們要先了解下terminal emulator,即終端模擬器,的運(yùn)行機(jī)制。

0x03 Terminal Emulator的運(yùn)行機(jī)制

我當(dāng)前使用的terminal emulator為 alacritty,后面如果涉及到terminal emulator的源碼分析,就是基于這個(gè)項(xiàng)目。

當(dāng)然,以下講的terminal emulator的運(yùn)行機(jī)制,對(duì)于其他terminal emulator也同樣適用。

當(dāng)我們?cè)趫D形化界面,打開(kāi)一個(gè)terminal emulator時(shí),terminal emulator會(huì)調(diào)用openpty函數(shù),向linux內(nèi)核申請(qǐng)一個(gè)pty數(shù)據(jù)通道,當(dāng)該pty數(shù)據(jù)通道創(chuàng)建成功后,linux內(nèi)核會(huì)返回兩個(gè)文件描述符,即兩個(gè)fd,給terminal emulator,這兩個(gè)fd,就代表了新創(chuàng)建pty數(shù)據(jù)通道的兩端,分別為master端和slave端。

當(dāng)向master端的fd寫(xiě)數(shù)據(jù)時(shí),該數(shù)據(jù)就可以從slave端的fd讀出來(lái),當(dāng)向slave端的fd寫(xiě)數(shù)據(jù)時(shí),該數(shù)據(jù)就能從master端的fd讀出來(lái)。

當(dāng)pty數(shù)據(jù)通道創(chuàng)建完畢后,terminal emulator就會(huì)調(diào)用fork函數(shù),啟動(dòng)一個(gè)子進(jìn)程,該子進(jìn)程用來(lái)運(yùn)行shell程序,比如bash、zsh等,同時(shí)會(huì)將該shell的標(biāo)準(zhǔn)輸入,標(biāo)準(zhǔn)輸出,標(biāo)準(zhǔn)錯(cuò)誤輸出,都設(shè)置為上面通過(guò)openpty函數(shù)獲取的slave端的fd。

shell在啟動(dòng)成功后,會(huì)一直等待著從標(biāo)準(zhǔn)輸入,即slave fd,里接收要執(zhí)行的命令。

當(dāng)terminal emulator啟動(dòng)成功后,我們就可以在其內(nèi)部輸入命令了,我們輸入的命令,會(huì)被terminal emulator寫(xiě)入到master fd里,這樣在shell子進(jìn)程中,就可以通過(guò)標(biāo)準(zhǔn)輸入,即slave fd,接收到這個(gè)命令,并開(kāi)始執(zhí)行。

shell在執(zhí)行接收到的命令時(shí),也是通過(guò)fork函數(shù),創(chuàng)建一個(gè)子進(jìn)程,然后在子進(jìn)程里執(zhí)行該命令對(duì)應(yīng)的程序。

不過(guò),這里需要注意的是,子進(jìn)程中運(yùn)行的命令程序,其標(biāo)準(zhǔn)輸入,標(biāo)準(zhǔn)輸出、標(biāo)準(zhǔn)錯(cuò)誤輸出都是繼承自shell,即它的標(biāo)準(zhǔn)輸入,標(biāo)準(zhǔn)輸出、標(biāo)準(zhǔn)錯(cuò)誤輸出的值都是slave fd。

這樣,當(dāng)命令程序?qū)懭罩镜綐?biāo)準(zhǔn)輸出時(shí),其實(shí)際上是寫(xiě)到了slave fd里,如此,在terminal emulator里,就可以通過(guò)master fd,讀取到這些日志信息,并在terminal emulator里顯示出來(lái)。

同樣的道理,當(dāng)我們此時(shí)在terminal emulator里輸入內(nèi)容時(shí),該內(nèi)容會(huì)被terminal emulator寫(xiě)入到master fd,進(jìn)而就可以被命令程序進(jìn)程,從標(biāo)準(zhǔn)輸入,即slave fd,里讀出來(lái)。

這里大家可能會(huì)有個(gè)疑問(wèn),即shell進(jìn)程和當(dāng)前運(yùn)行的命令程序進(jìn)程,他們的標(biāo)準(zhǔn)輸入都是slave fd,那為什么我們寫(xiě)入到terminal emulator里的內(nèi)容,是被命令程序進(jìn)程讀出來(lái),而不是被shell進(jìn)程讀出來(lái)呢?

這個(gè)就涉及到terminal emulator使用權(quán)的概念了。

當(dāng)shell進(jìn)程剛啟動(dòng)成功后,terminal emulator的使用權(quán)自然是shell的,此時(shí)我們?cè)趖erminal emulator里輸入的內(nèi)容,會(huì)被shell從標(biāo)準(zhǔn)輸入,即slave fd,里讀出來(lái)。

當(dāng)shell啟動(dòng)一個(gè)子進(jìn)程,并用該進(jìn)程運(yùn)行命令程序時(shí),它會(huì)把terminal emulator的使用權(quán),轉(zhuǎn)交給該命令程序進(jìn)程,此時(shí)我們?cè)趖erminal emulator里輸入的內(nèi)容,會(huì)被該命令程序進(jìn)程從它的標(biāo)準(zhǔn)輸入,即slave fd,里讀出來(lái)的。

當(dāng)該命令程序進(jìn)程退出后,linux內(nèi)核會(huì)通知shell進(jìn)程,告知它啟動(dòng)的子命令進(jìn)程已經(jīng)結(jié)束了,此時(shí)shell會(huì)把terminal emulator的使用權(quán)轉(zhuǎn)回給自己,進(jìn)而shell又可以開(kāi)始從terminal emulator接收新的命令了。

下面我們來(lái)看一些具體的例子:

c90ce0de-4dd7-11ee-a25d-92fbcf53809c.png

上圖是用ps命令輸出的信息,看圖中的選中行,第一行為alacritty進(jìn)程,即我們最開(kāi)始啟動(dòng)的terminal emulator,第二行為alacritty啟動(dòng)的子進(jìn)程,在該子進(jìn)程中,運(yùn)行的是bash程序,第三行為bash啟動(dòng)的子進(jìn)程,在該子進(jìn)程中,運(yùn)行的是我們文章最開(kāi)始時(shí)使用的測(cè)試程序hello。

這三個(gè)進(jìn)程的層級(jí)關(guān)系,和我們上面的描述是一致的。

我們?cè)賮?lái)看下alacritty啟動(dòng)bash子進(jìn)程的相關(guān)代碼:

c92467ae-4dd7-11ee-a25d-92fbcf53809c.png

上圖中make_pty函數(shù)內(nèi)會(huì)調(diào)用openpty函數(shù)獲取master fd和slave fd,在獲取到master fd和slave fd后,slave fd被賦值到builder的stdin, stdout, stderr里,這樣,在下面執(zhí)行builder.spawn函數(shù)啟動(dòng)shell子進(jìn)程時(shí),其標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)錯(cuò)誤輸出就都指向slave fd了。

另外,在上圖中,master fd被保存到了Pty里,并和其他信息一起返回給該函數(shù)的調(diào)用方,這樣,alacritty如果想要發(fā)送數(shù)據(jù)給shell時(shí),就從Pty里獲取到master fd,然后將數(shù)據(jù)寫(xiě)入到master fd里就好了。

0x04 Ctrl-C是如何處理的

上面我們講過(guò),我們?cè)趖erminal emulator中輸入的內(nèi)容,會(huì)被terminal emulator寫(xiě)到內(nèi)核的pty數(shù)據(jù)通道中,進(jìn)而這些數(shù)據(jù)會(huì)被轉(zhuǎn)發(fā)給shell進(jìn)程,或者是在shell中運(yùn)行的子進(jìn)程。

那在terminal emulator里按Ctrl-C,也是這么處理的嗎?

首先,Ctrl-C確實(shí)是被當(dāng)作一個(gè)字符來(lái)處理的,且terminal emulator在接收到這個(gè)字符后,會(huì)直接寫(xiě)入到內(nèi)核的pty數(shù)據(jù)通道,并不做特殊處理。

但是,在內(nèi)核的pty數(shù)據(jù)通道里,有一個(gè)組件叫做 line discipline,它會(huì)檢查要被傳輸?shù)淖址绻址髦邪珻trl-C,它就會(huì)把Ctrl-C這個(gè)特殊字符從字符流中移除掉,并生成一個(gè)SIGINT信號(hào),發(fā)送給目標(biāo)進(jìn)程。

如果目標(biāo)進(jìn)程沒(méi)有捕獲該信號(hào),內(nèi)核就會(huì)執(zhí)行該信號(hào)的默認(rèn)行為,即殺掉目標(biāo)進(jìn)程。

以下是生成SIGINT信號(hào)的內(nèi)核代碼:

c944312e-4dd7-11ee-a25d-92fbcf53809c.png

上圖中,光標(biāo)所在行就是在判斷該字符是否是Ctrl-C,如果是,則發(fā)送SIGINT信號(hào)給目標(biāo)進(jìn)程。

由上圖我們還可以看到,其實(shí)不止Ctrl-C這個(gè)特殊字符會(huì)轉(zhuǎn)化成信號(hào),QUIT字符Ctrl-,SUSP字符Ctrl-Z等,都會(huì)被轉(zhuǎn)化成對(duì)應(yīng)的信號(hào)。

0x05 精致全景圖

以上講了很多理論,下面我們來(lái)畫(huà)一幅圖,來(lái)梳理下完整流程。

wKgaomT6eBWAEzM5AABvYuVspz8583.jpg

首先,在terminal emulator啟動(dòng)成功后,我們?cè)谄渲休斎?/hello命令,該命令沿著terminal emulator中的第一個(gè)輸出箭頭,即第一條虛線,經(jīng)由內(nèi)核pty數(shù)據(jù)通道,到達(dá)bash進(jìn)程的stdin。

然后,bash從標(biāo)準(zhǔn)輸入中讀取到要執(zhí)行的命令./hello,fork一個(gè)新的子進(jìn)程,并在子進(jìn)程中開(kāi)始執(zhí)行hello程序,此時(shí)bash也把terminal emulator的使用權(quán)交給了hello進(jìn)程。

hello程序在開(kāi)始運(yùn)行后,就嘗試從標(biāo)準(zhǔn)輸入中讀取數(shù)據(jù)。

接著,我們?cè)趖erminal emulator中再輸入hello world,該數(shù)據(jù)會(huì)沿著terminal emulator中的第二個(gè)輸出箭頭,即第一條實(shí)線,經(jīng)由pty數(shù)據(jù)通道,到達(dá)hello進(jìn)程的stdin。

hello進(jìn)程從標(biāo)準(zhǔn)輸入中讀到hello world字符串,然后直接將其寫(xiě)入到了標(biāo)準(zhǔn)輸出,該數(shù)據(jù)又經(jīng)由內(nèi)核pty數(shù)據(jù)通道,到達(dá)terminal emulator的master fd端。

terminal emulator從master fd中讀取到hello world字符串,并將其顯示在界面中。

hello進(jìn)程在寫(xiě)完hello world字符串后,自己主動(dòng)退出,bash檢測(cè)到hello進(jìn)程退出后,又把terminal emulator的使用權(quán)轉(zhuǎn)回給自己。

bash寫(xiě)命令提示符>到標(biāo)準(zhǔn)輸出,該數(shù)據(jù)再經(jīng)由pty數(shù)據(jù)通道到達(dá)terminal emulator的master fd端。

terminal emulator從master fd中讀取到bash的命令提示符,并將其顯示在界面上,提示用戶可以輸入下一條命令了。

以上就是在terminal emulator中執(zhí)行hello程序的完整流程。

從上圖中我們還可以看到,假設(shè)我們?cè)趖erminal emulator中按Ctrl-C,該數(shù)據(jù)在到達(dá)內(nèi)核pty數(shù)據(jù)通道時(shí),line discipline組件會(huì)將其轉(zhuǎn)換成SIGINT信號(hào),并發(fā)給目標(biāo)進(jìn)程。

這個(gè)也解答了我們此篇文章的疑問(wèn),現(xiàn)在你應(yīng)該豁然開(kāi)朗了吧。

另外,內(nèi)核中 line discripline 組件的能力也是可以被修改的,比如我們可以修改成按Ctrl-B觸發(fā)SIGINT信號(hào),甚至是直接關(guān)閉SIGINT信號(hào)的生成,具體方式,可以查看stty命令的man文檔。







審核編輯:劉清

聲明:本文內(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)投訴
  • 觸發(fā)器
    +關(guān)注

    關(guān)注

    14

    文章

    2065

    瀏覽量

    63574
  • 模擬器
    +關(guān)注

    關(guān)注

    2

    文章

    1026

    瀏覽量

    45863
  • LINUX內(nèi)核
    +關(guān)注

    關(guān)注

    1

    文章

    321

    瀏覽量

    23304
  • Shell
    +關(guān)注

    關(guān)注

    1

    文章

    375

    瀏覽量

    25492
  • rust語(yǔ)言
    +關(guān)注

    關(guān)注

    0

    文章

    57

    瀏覽量

    3301

原文標(biāo)題:為什么Ctrl-C會(huì)中斷當(dāng)前運(yùn)行程序

文章出處:【微信號(hào):良許Linux,微信公眾號(hào):良許Linux】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    Linux C語(yǔ)言獲取當(dāng)前程序名稱的三種方式

    如果需要在程序內(nèi)部獲取當(dāng)前運(yùn)行程序的名稱,可以使用如下 4 種方式:
    發(fā)表于 08-24 16:03 ?3448次閱讀
    Linux <b class='flag-5'>C</b>語(yǔ)言獲取<b class='flag-5'>當(dāng)前程序</b>名稱的三種方式

    這個(gè)程序怎樣通過(guò)布爾量退出循環(huán)?

    本帖最后由 lazybear 于 2013-1-17 14:12 編輯 一旦運(yùn)行程序 就無(wú)法退出了 怎么能夠解決這個(gè)問(wèn)題?
    發(fā)表于 01-17 14:10

    運(yùn)行程序出問(wèn)題啦!!!

    我以前生成的運(yùn)行程序都能正常運(yùn)行,最近不知為什么生成的運(yùn)行程序不是代碼不全就是調(diào)用的時(shí)候會(huì)出現(xiàn)重置,有事調(diào)用程序都調(diào)不出來(lái)......我做了一個(gè)登入界面,然后登入到主
    發(fā)表于 07-29 15:52

    Ctrl-C在使用OGL的應(yīng)用程序中不起作用是怎么樣?

    我們有一個(gè)使用 OpenGL 的應(yīng)用程序。該應(yīng)用程序為一些信號(hào)(包括 SIGINT)設(shè)置了一個(gè)信號(hào)處理程序。我們注意到 Ctrl-C 信號(hào)處理程序
    發(fā)表于 03-27 08:08

    步進(jìn)電機(jī)加速-勻速-減速運(yùn)行程序(C51源程序)

    步進(jìn)電機(jī)加速-勻速-減速運(yùn)行程序(C51) ME300系列單片機(jī)開(kāi)發(fā)系統(tǒng)+步進(jìn)電機(jī)模塊演示程序 功能:
    發(fā)表于 12-28 10:10 ?7234次閱讀

    步進(jìn)電機(jī)加速-勻速-減速運(yùn)行程序(ASM)

    步進(jìn)電機(jī)加速-勻速-減速運(yùn)行程序(ASM) 功能:    步進(jìn)電機(jī)以加速方式啟動(dòng),轉(zhuǎn)速達(dá)到程序規(guī)定的最快速度后保持一段時(shí)間
    發(fā)表于 12-28 10:12 ?5341次閱讀

    為什么區(qū)塊鏈1.0不能運(yùn)行程序

    那么,DAPP究竟是什么?在區(qū)塊鏈上運(yùn)行程序到底是怎么一回事? 在之前我們說(shuō)到:BTC用區(qū)塊鏈記賬和使用UTXO,而ETH用區(qū)塊鏈運(yùn)行程序代碼和使用賬戶余額制。 區(qū)塊鏈2.0, 是可編程區(qū)塊鏈,我們可以在區(qū)塊鏈2.0上面,運(yùn)
    發(fā)表于 11-25 11:45 ?1387次閱讀

    關(guān)于MCU怎么在擴(kuò)展的SDRAM上運(yùn)行程序?

    MCU怎么在擴(kuò)展的SDRAM上運(yùn)行程序?
    的頭像 發(fā)表于 03-01 13:17 ?3370次閱讀
    關(guān)于MCU怎么在擴(kuò)展的SDRAM上<b class='flag-5'>運(yùn)行程序</b>?

    在STVDCOSMIC在RAM中運(yùn)行代碼stm8 ram中運(yùn)行程序

    在STVDCOSMIC在RAM中運(yùn)行代碼stm8 ram中運(yùn)行程序(電源技術(shù)期刊主編)-在STVDCOSMIC在RAM中運(yùn)行代碼stm8 ram中運(yùn)行程序? ? ? ? ?
    發(fā)表于 09-17 17:12 ?12次下載
    在STVDCOSMIC在RAM中<b class='flag-5'>運(yùn)行</b>代碼stm8 ram中<b class='flag-5'>運(yùn)行程序</b>

    vcu-ctrl-sw里decoder的退出機(jī)制

    有工程師詢問(wèn)vcu-ctrl-sw里decoder的退出機(jī)制。 下面的內(nèi)容,根據(jù)vcu-ctrl-sw 2020.2分析。
    發(fā)表于 08-02 17:39 ?970次閱讀

    Linux下運(yùn)行后臺(tái)任務(wù)的幾種方法

    程序員最不能容忍的是在使用終端的時(shí)候往往因?yàn)榫W(wǎng)絡(luò),關(guān)閉屏幕,執(zhí)行CTRL+C等原因造成ssh斷開(kāi)造成正在運(yùn)行程序退出,使得我們的工作功虧一簣。
    的頭像 發(fā)表于 12-05 11:13 ?1486次閱讀

    linux中防止運(yùn)行程序退出的幾種執(zhí)行方法

    其背后的主要原因在于上述的相關(guān)操作,shell默認(rèn)會(huì)發(fā)送中斷信號(hào)給該終端session關(guān)聯(lián)的進(jìn)程,從而導(dǎo)致進(jìn)程跟隨終端退出,為了弄清這個(gè)問(wèn)題我們首先要了解兩種中斷信號(hào):
    發(fā)表于 07-03 11:37 ?3077次閱讀

    OOM會(huì)導(dǎo)致JVM虛擬機(jī)退出

    熟悉Java開(kāi)發(fā)的人,應(yīng)該會(huì)經(jīng)常遇到的異常:OOM,那么這個(gè)異常會(huì)導(dǎo)致 JVM 虛擬機(jī)退出嗎? 1、結(jié)論 Java虛擬機(jī)(JVM)在運(yùn)行Java應(yīng)用時(shí),可能會(huì)遇到內(nèi)存不足的情況,從而拋
    的頭像 發(fā)表于 09-30 10:14 ?1500次閱讀

    運(yùn)行c程序的基本步驟

    運(yùn)行C程序的基本步驟可以分為以下四個(gè)主要步驟:編寫(xiě)程序、編譯程序、鏈接程序
    的頭像 發(fā)表于 11-27 16:21 ?8850次閱讀

    idea如何多次運(yùn)行程序

    在計(jì)算機(jī)編程的世界中,我們通常需要多次運(yùn)行程序來(lái)測(cè)試其性能、調(diào)試錯(cuò)誤或者進(jìn)行大規(guī)模的數(shù)據(jù)處理。但是有些編程初學(xué)者可能會(huì)困惑于如何多次運(yùn)行程序的問(wèn)題。本文將會(huì)詳細(xì)介紹如何多次運(yùn)行程序的不
    的頭像 發(fā)表于 12-06 14:59 ?2572次閱讀
    沙湾县| 北安市| 册亨县| 镇远县| 石台县| 仙居县| 攀枝花市| 余江县| 谷城县| 富锦市| 嘉义市| 特克斯县| 安陆市| 西盟| 湘潭市| 出国| 通城县| 双牌县| 牡丹江市| 楚雄市| 枝江市| 化德县| 普兰县| 兖州市| 甘洛县| 娄底市| 大同县| 从化市| 神农架林区| 乌恰县| 紫阳县| 南昌市| 卓资县| 望城县| 吕梁市| 杭锦后旗| 肃北| 海阳市| 潢川县| 容城县| 新蔡县|