Linux ctrl-c explained(ctrl-c 詳解)

目錄

  • 1 背景姿勢
  • 2 前戲
  • 3 正餐
  • 4 systemctl stop docker
  • 5 demo

1 背景姿勢

驅動

驅動程序全稱設備驅動程序,是添加到操作系統中的特殊程序,其中包含有關硬件設備的信息。此信息能夠使計算機與相應的設備進行通信。

中斷

觸發系統將運行時間由用戶態程序交還給內核態的一種方式。

終端

終端

僞終端(pseudo terminal) --> /dev/pts/8

會話

信號

發送給程序的來表示有重要事件發生的軟件中斷。
系統收到信號後,會把 CPU 時間交由內核態,然後再進行退出程序,掛起,恢復,或自定義操作。

常見信號

signals

信號 按鍵 意義
SIGINT Ctrl-C 退出當前 session 所有前臺進程
SIGTSTP Ctrl-Z 掛起前臺進程
SIGTERM 優雅殺掉指定進程,可被阻塞
SIGKILL 強制殺掉指定進程
Ctrl-D 不是 signal, write EOF to input

發送信號

kill -SIG pid

自定義信號

trap "echo 'signal SIGINT received'" SIGINT

延伸 Tips 1:

nohup 的由來:

nohup python3 manage.py runserver &

當終端中斷時(拔網線,wifi 斷網等),相關驅動程序會給當前會話
(session, 簡單來說一個 login shell 就是一次會話)
中所有程序(前臺和後臺)發送 hang up(HUP) 信號,使程序退出。

延伸 Tips 2:

Ctrl- signal SIGQUIT
Ctrl+J實際上是一個換行符。
按下Ctrl+I與按下Tab鍵的效果相同。
Ctrl+[與ESC相同。
Ctrl+H代替BackSpace鍵。
鼠標右鍵快捷鍵:VK_APPS (93)


2 前戲 - linux 進程生命週期

process-flow


3 正餐

flow


4 systemctl stop docker

案發現場

耗子叔的一篇博客

reason

systemd 是個啥麼玩意

系統的 init 程序,進程調度管理程序,id 爲 1,所有進程的爹

systemctl 是systemd 的 shell interface,常見的操作: systemctl start|stop|status|reload

systemctl stop

docker service 的行爲定義在/usr/lib/systemd/system/docker.service

systemd stop 的 man: the process is terminated by sending the signal specified in KillSignal=(SIGTERM) when service stop is requested.

dockerd trap

systemctl stop dockerd 執行後會給 dockerd 發送 SIGTERM 信號,dockerd 捕獲到這個信號後,會去調用 cleanup 清理程序清理掉它下面的容器,同時計數器加一,當收到3次 SIGTERM 或 SIGINT(比如按下 ctrl-c)後,會出發 “force exit without cleanup”,強行退出 dockerd ,就會導致 dockerd 退出,但容器不退出,因而容器佔用但資源(ip 地址等)不會被釋放。此外,如果 kill -9,會發送 SIGKILL,強行殺掉 dockerd,也是不會清除容器但。所以慎用 ctrl-c ,慎用 kill -9 啊!!

// * If SIGINT or SIGTERM are received, `cleanup` is called, then the process is terminated.
// * If SIGINT or SIGTERM are received 3 times before cleanup is complete, then cleanup is
//   skipped and the process is terminated immediately (allows force quit of stuck daemon)
// * A SIGQUIT always causes an exit without cleanup, with a goroutine dump preceding exit.
c := make(chan os.Signal, 1)
    // we will handle INT, TERM, QUIT, SIGPIPE here
    signals := []os.Signal{os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGPIPE}
    gosignal.Notify(c, signals...)
    go func() {
        interruptCount := uint32(0)
        for sig := range c {
            if sig == syscall.SIGPIPE {
                continue
            }

            go func(sig os.Signal) {
                logger.Info(fmt.Sprintf("Processing signal '%v'", sig))
                switch sig {
                case os.Interrupt, syscall.SIGTERM:
                    if atomic.LoadUint32(&interruptCount) < 3 {
                        // Initiate the cleanup only once
                        if atomic.AddUint32(&interruptCount, 1) == 1 {
                            // Call the provided cleanup handler
                            cleanup()
                            os.Exit(0)
                        } else {
                            return
                        }
                    } else {
                        // 3 SIGTERM/INT signals received; force exit without cleanup
                        logger.Info("Forcing docker daemon shutdown without cleanup; 3 interrupts received")
                    }
                case syscall.SIGQUIT:
                    DumpStacks("")
                    logger.Info("Forcing docker daemon shutdown without cleanup on SIGQUIT")
                }

code is here.

延伸 Tips3:

如何刪除進程和子進程:

進程和子進程在同一組中,可根據 PGID kill 掉一組進程

kill -- -$PGID   Kill using the default signal (TERM = 15)
kill -9 -$PGID   Kill using the KILL signal (9)

other methods


5 I want more

《Unix 環境高級編程》
Learn C!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章