百日半狂乱

Shut the fuck up and write some code!!

SIGSTOPで停止したプロセスにSIGTERMを送ってもプロセスが死なない?

二十五日半狂乱3日目の記事

もはや、Advent Calendarでもなんでもなくなっているけど、そんな悲しい現実はさておいて.

前回の話stackoverflowですでに議論され尽くされていて、解答の一つに自分のスクリプト似た構造のシェルスクリプトがあった.

#!/bin/bash

killtree() {
    local _pid=$1
    local _sig=${2:-TERM}
    kill -stop ${_pid} # needed to stop quickly forking parent from producing child between child killing and parent killing
    for _child in $(ps -o pid --no-headers --ppid ${_pid}); do
        killtree ${_child} ${_sig}
    done
    kill -${_sig} ${_pid}
}

if [ $# -eq 0 -o $# -gt 2 ]; then
    echo "Usage: $(basename $0) <pid> [signal]"
    exit 1
fi

killtree $@

シグナルを指定できるし、親プロセスをstopしてから子スレッドの操作をするしで、悲しいかなこっちの方が断然良い出来だ.

そんなことを思いつつ、この投稿に対するコメントを眺めていると、

Stopped processes don't get killed with SIGTERM. See my answer – x-yuri Nov 20 '12 at 20:32

などという指摘があった.

中断したプロセスにkill TERMしてもプロセスが殺されないとは知らなかった.

もう少し遊んでみることにする.

SIGSTOPしたプロセスにSIGTERMしてみる

前回の記事で作成したmkpstree.bashでプロセスツリーを作ってそれに対して上記のkiltreeでいろんなシグナルを送信する.

このkilltreeはkillコマンドでシグナルを送信する前に予めSIGSTOPでプロセスを停止している点に注意しなければならない.

状況を把握するために、上記のkilltreeにecho "kill -${_sig} ${_pid}てな感じのechoを仕込んで様子を観察してみる*1

$ bash mkpstree.bash &
[1] 4609
$ pstree -pha 4609
bash,4609 mkpstree.bash
  |-sleep,4610 12345
  |-sleep,4611 12345
  |-sleep,4612 67890
  |-sleep,4613 67890
  `-sleep,4614 10000
$ bash killtree.bash 4609
kill -TERM 4610
kill -TERM 4611
kill -TERM 4612
kill -TERM 4613
kill -TERM 4614
kill -TERM 4609

[1]+  Stopped                 bash mkpstree.bash

確かに、TERMを送ってStoppedとはこれ如何に.

停止しているんだから再開してみた.

$ bash killtree.bash 4609 CONT
kill -CONT 4610
kill -CONT 4611
kill -CONT 4612
kill -CONT 4613
kill -CONT 4614
kill -CONT 4609
[1]+  Terminated              bash mkpstree.bash

なんと再開したらTerminatedとなった.

sleep 100 &などの適当なプロセスに対して、SIGSTOP、SIGTERM、SIGCONTの順でシグナルを送っても同じ状況を再現できる.

これは単にSIGTERMのポリシー的に、プロセス終了時の後始末をきっちり出来ない以上、強制終了などという暴挙には移れないということだろうか?うーん.

SIGKILLしてみる

stackoverflowのコメントに、殺したければSIGKILLを送れば良くないか?とあったのでSIGKILLも送ってみる.

$ bash mkpstree.bash &
[1] 4632
$ pstree -pha 4632
bash,4632 mkpstree.bash
  |-sleep,4633 12345
  |-sleep,4634 12345
  |-sleep,4635 67890
  |-sleep,4636 67890
  `-sleep,4637 10000
$ bash killtree.bash 4632 KILL
kill -KILL 4633
kill -KILL 4634
kill -KILL 4635
kill -KILL 4636
kill -KILL 4637
kill -KILL 4632
[1]+  Killed                  bash mkpstree.bash

無事に一発でプロセスツリーをkillできた.

しかしまぁ、このkilltreeは自分が作ったものなんかよりも余程便利な代物である.

*1:ここではシグナルの名前をSIGTERMからTERMに省略している