在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

為什么Ctrl-C會導致當前運行程序退出呢?

dyquk4xk2p3d ? 來源:ytcoode ? 2023-09-08 09:23 ? 次閱讀

0x01 問題演示

下面是用rust寫的一段測試程序,邏輯非常簡單,就是讀取用戶輸入,然后將其輸出。

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

運行這個程序,然后按Ctrl-C:

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

由上圖可見,該程序沒有收到任何輸入,當然也沒有任何輸出,這個程序就退出了。

為什么Ctrl-C會導致當前運行程序退出呢?

0x02 程序退出原因

上面的測試程序之所以會退出,是因為Ctrl-C會告訴linux內核,讓其發送SIGINT信號給當前運行程序,該信號的默認行為是殺掉目標進程,所以就有了上面的現象。

但是,SIGINT信號,以及其他的各種信號,都是可以捕獲的,這樣我們就可以修改信號的默認行為,比如將SIGINT信號的默認行為,修改成輸出一些日志,而不是殺掉當前進程。

將上面的測試代碼改成下面的樣子:

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

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

運行看下:

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

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

由上可見,Ctrl-C導致程序退出,確實是因為該按鍵使內核發送了SIGINT信號到目標進程,進而導致目標進程被殺死。

那為什么Ctrl-C會觸發SIGINT信號呢?

在回答這個問題之前,我們要先了解下terminal emulator,即終端模擬器,的運行機制。

0x03 Terminal Emulator的運行機制

我當前使用的terminal emulator為 alacritty,后面如果涉及到terminal emulator的源碼分析,就是基于這個項目。

當然,以下講的terminal emulator的運行機制,對于其他terminal emulator也同樣適用。

當我們在圖形化界面,打開一個terminal emulator時,terminal emulator會調用openpty函數,向linux內核申請一個pty數據通道,當該pty數據通道創建成功后,linux內核會返回兩個文件描述符,即兩個fd,給terminal emulator,這兩個fd,就代表了新創建pty數據通道的兩端,分別為master端和slave端。

當向master端的fd寫數據時,該數據就可以從slave端的fd讀出來,當向slave端的fd寫數據時,該數據就能從master端的fd讀出來。

當pty數據通道創建完畢后,terminal emulator就會調用fork函數,啟動一個子進程,該子進程用來運行shell程序,比如bash、zsh等,同時會將該shell的標準輸入,標準輸出,標準錯誤輸出,都設置為上面通過openpty函數獲取的slave端的fd。

shell在啟動成功后,會一直等待著從標準輸入,即slave fd,里接收要執行的命令。

當terminal emulator啟動成功后,我們就可以在其內部輸入命令了,我們輸入的命令,會被terminal emulator寫入到master fd里,這樣在shell子進程中,就可以通過標準輸入,即slave fd,接收到這個命令,并開始執行。

shell在執行接收到的命令時,也是通過fork函數,創建一個子進程,然后在子進程里執行該命令對應的程序。

不過,這里需要注意的是,子進程中運行的命令程序,其標準輸入,標準輸出、標準錯誤輸出都是繼承自shell,即它的標準輸入,標準輸出、標準錯誤輸出的值都是slave fd。

這樣,當命令程序寫日志到標準輸出時,其實際上是寫到了slave fd里,如此,在terminal emulator里,就可以通過master fd,讀取到這些日志信息,并在terminal emulator里顯示出來。

同樣的道理,當我們此時在terminal emulator里輸入內容時,該內容會被terminal emulator寫入到master fd,進而就可以被命令程序進程,從標準輸入,即slave fd,里讀出來。

這里大家可能會有個疑問,即shell進程和當前運行的命令程序進程,他們的標準輸入都是slave fd,那為什么我們寫入到terminal emulator里的內容,是被命令程序進程讀出來,而不是被shell進程讀出來呢?

這個就涉及到terminal emulator使用權的概念了。

當shell進程剛啟動成功后,terminal emulator的使用權自然是shell的,此時我們在terminal emulator里輸入的內容,會被shell從標準輸入,即slave fd,里讀出來。

當shell啟動一個子進程,并用該進程運行命令程序時,它會把terminal emulator的使用權,轉交給該命令程序進程,此時我們在terminal emulator里輸入的內容,會被該命令程序進程從它的標準輸入,即slave fd,里讀出來的。

當該命令程序進程退出后,linux內核會通知shell進程,告知它啟動的子命令進程已經結束了,此時shell會把terminal emulator的使用權轉回給自己,進而shell又可以開始從terminal emulator接收新的命令了。

下面我們來看一些具體的例子:

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

上圖是用ps命令輸出的信息,看圖中的選中行,第一行為alacritty進程,即我們最開始啟動的terminal emulator,第二行為alacritty啟動的子進程,在該子進程中,運行的是bash程序,第三行為bash啟動的子進程,在該子進程中,運行的是我們文章最開始時使用的測試程序hello。

這三個進程的層級關系,和我們上面的描述是一致的。

我們再來看下alacritty啟動bash子進程的相關代碼:

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

上圖中make_pty函數內會調用openpty函數獲取master fd和slave fd,在獲取到master fd和slave fd后,slave fd被賦值到builder的stdin, stdout, stderr里,這樣,在下面執行builder.spawn函數啟動shell子進程時,其標準輸入、標準輸入、標準錯誤輸出就都指向slave fd了。

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

0x04 Ctrl-C是如何處理的

上面我們講過,我們在terminal emulator中輸入的內容,會被terminal emulator寫到內核的pty數據通道中,進而這些數據會被轉發給shell進程,或者是在shell中運行的子進程。

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

首先,Ctrl-C確實是被當作一個字符來處理的,且terminal emulator在接收到這個字符后,會直接寫入到內核的pty數據通道,并不做特殊處理。

但是,在內核的pty數據通道里,有一個組件叫做 line discipline,它會檢查要被傳輸的字符,如果字符流中包含Ctrl-C,它就會把Ctrl-C這個特殊字符從字符流中移除掉,并生成一個SIGINT信號,發送給目標進程。

如果目標進程沒有捕獲該信號,內核就會執行該信號的默認行為,即殺掉目標進程。

以下是生成SIGINT信號的內核代碼:

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

上圖中,光標所在行就是在判斷該字符是否是Ctrl-C,如果是,則發送SIGINT信號給目標進程。

由上圖我們還可以看到,其實不止Ctrl-C這個特殊字符會轉化成信號,QUIT字符Ctrl-,SUSP字符Ctrl-Z等,都會被轉化成對應的信號。

0x05 精致全景圖

以上講了很多理論,下面我們來畫一幅圖,來梳理下完整流程。

wKgaomT6eBWAEzM5AABvYuVspz8583.jpg

首先,在terminal emulator啟動成功后,我們在其中輸入./hello命令,該命令沿著terminal emulator中的第一個輸出箭頭,即第一條虛線,經由內核pty數據通道,到達bash進程的stdin。

然后,bash從標準輸入中讀取到要執行的命令./hello,fork一個新的子進程,并在子進程中開始執行hello程序,此時bash也把terminal emulator的使用權交給了hello進程。

hello程序在開始運行后,就嘗試從標準輸入中讀取數據。

接著,我們在terminal emulator中再輸入hello world,該數據會沿著terminal emulator中的第二個輸出箭頭,即第一條實線,經由pty數據通道,到達hello進程的stdin。

hello進程從標準輸入中讀到hello world字符串,然后直接將其寫入到了標準輸出,該數據又經由內核pty數據通道,到達terminal emulator的master fd端。

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

hello進程在寫完hello world字符串后,自己主動退出,bash檢測到hello進程退出后,又把terminal emulator的使用權轉回給自己。

bash寫命令提示符>到標準輸出,該數據再經由pty數據通道到達terminal emulator的master fd端。

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

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

從上圖中我們還可以看到,假設我們在terminal emulator中按Ctrl-C,該數據在到達內核pty數據通道時,line discipline組件會將其轉換成SIGINT信號,并發給目標進程。

這個也解答了我們此篇文章的疑問,現在你應該豁然開朗了吧。

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







審核編輯:劉清

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 觸發器
    +關注

    關注

    14

    文章

    2009

    瀏覽量

    61364
  • 模擬器
    +關注

    關注

    2

    文章

    882

    瀏覽量

    43430
  • LINUX內核
    +關注

    關注

    1

    文章

    316

    瀏覽量

    21747
  • Shell
    +關注

    關注

    1

    文章

    366

    瀏覽量

    23459
  • rust語言
    +關注

    關注

    0

    文章

    57

    瀏覽量

    3029

原文標題:為什么Ctrl-C會中斷當前運行程序

文章出處:【微信號:良許Linux,微信公眾號:良許Linux】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    Linux C語言獲取當前程序名稱的三種方式

    如果需要在程序內部獲取當前運行程序的名稱,可以使用如下 4 種方式:
    發表于 08-24 16:03 ?2465次閱讀
    Linux <b class='flag-5'>C</b>語言獲取<b class='flag-5'>當前程序</b>名稱的三種方式

    這個程序怎樣通過布爾量退出循環?

    本帖最后由 lazybear 于 2013-1-17 14:12 編輯 一旦運行程序 就無法退出了 怎么能夠解決這個問題
    發表于 01-17 14:10

    運行程序出問題啦!!!

    我以前生成的運行程序都能正常運行,最近不知為什么生成的運行程序不是代碼不全就是調用的時候會出現重置,有事調用程序都調不出來......我做了一個登入界面,然后登入到主
    發表于 07-29 15:52

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

    我們有一個使用 OpenGL 的應用程序。該應用程序為一些信號(包括 SIGINT)設置了一個信號處理程序。我們注意到 Ctrl-C 信號處理程序
    發表于 03-27 08:08

    步進電機加速-勻速-減速運行程序(C51源程序)

    步進電機加速-勻速-減速運行程序(C51) ME300系列單片機開發系統+步進電機模塊演示程序 功能:
    發表于 12-28 10:10 ?6974次閱讀

    步進電機加速-勻速-減速運行程序(ASM)

    步進電機加速-勻速-減速運行程序(ASM) 功能:    步進電機以加速方式啟動,轉速達到程序規定的最快速度后保持一段時間
    發表于 12-28 10:12 ?5059次閱讀

    為什么區塊鏈1.0不能運行程序

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

    關于MCU怎么在擴展的SDRAM上運行程序

    MCU怎么在擴展的SDRAM上運行程序
    的頭像 發表于 03-01 13:17 ?2256次閱讀
    關于MCU怎么在擴展的SDRAM上<b class='flag-5'>運行程序</b>?

    在STVDCOSMIC在RAM中運行代碼stm8 ram中運行程序

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

    vcu-ctrl-sw里decoder的退出機制

    有工程師詢問vcu-ctrl-sw里decoder的退出機制。 下面的內容,根據vcu-ctrl-sw 2020.2分析。
    發表于 08-02 17:39 ?607次閱讀

    Linux下運行后臺任務的幾種方法

    程序員最不能容忍的是在使用終端的時候往往因為網絡,關閉屏幕,執行CTRL+C等原因造成ssh斷開造成正在運行程序退出,使得我們的工作功虧一簣。
    的頭像 發表于 12-05 11:13 ?900次閱讀

    linux中防止運行程序退出的幾種執行方法

    其背后的主要原因在于上述的相關操作,shell默認會發送中斷信號給該終端session關聯的進程,從而導致進程跟隨終端退出,為了弄清這個問題我們首先要了解兩種中斷信號:
    發表于 07-03 11:37 ?2502次閱讀

    OOM導致JVM虛擬機退出

    熟悉Java開發的人,應該會經常遇到的異常:OOM,那么這個異常會導致 JVM 虛擬機退出嗎? 1、結論 Java虛擬機(JVM)在運行Java應用時,可能遇到內存不足的情況,從而拋
    的頭像 發表于 09-30 10:14 ?836次閱讀

    運行c程序的基本步驟

    運行C程序的基本步驟可以分為以下四個主要步驟:編寫程序、編譯程序、鏈接程序
    的頭像 發表于 11-27 16:21 ?6087次閱讀

    idea如何多次運行程序

    在計算機編程的世界中,我們通常需要多次運行程序來測試其性能、調試錯誤或者進行大規模的數據處理。但是有些編程初學者可能困惑于如何多次運行程序的問題。本文將會詳細介紹如何多次運行程序的不
    的頭像 發表于 12-06 14:59 ?1605次閱讀
    主站蜘蛛池模板: 手机看片自拍自自拍日韩免费 | 一色屋成人免费精品网 | 婷婷久久久五月综合色 | 啪啪调教所29下拉式免费阅读 | 精品色综合 | 夜色321看片资源站 夜色sese | 97精品伊人久久久大香线焦 | 国产主播在线观看 | 视频一区中文字幕 | 能可以直接看的av网址 | 国产精品免费看久久久 | 午夜湿 | 日本人69xxxxxxx69 | 亚洲欧美在线一区二区 | 日本护士69xx00 | 黄视频网站在线观看 | 美女被免费网站视频九色 | 国产免费爽爽视频免费可以看 | 久久青草91免费观看 | 欧美人与牲动交xxxx | 国产亚洲午夜精品a一区二区 | 国内精品久久久久久影院老狼 | 久久国产影视 | 种子天堂bt磁力在线资源 | 亚洲影院手机版777点击进入影院 | 国产视频首页 | 老司机精品视频免费 | 国产资源在线视频 | 182tv免费视视频线路一二三 | 亚洲第一视频区 | 国产精品免费拍拍拍 | 天天视频天天爽 | 3344成年在线视频免费播放男男 | 夜夜操夜夜操 | 天天做人人爱夜夜爽2020 | xxxx曰本| 人人干人人模 | 国产色丁香久久综合 | 曰韩高清一级毛片 | 中文字幕一二三四区2021 | 手机福利在线观看 |