Gen's blog

CTFとか、競プロとか、その他諸々

SIGINTを受け取ったときのsleepの終了状態で詰まった話

誰も書かなそうなので、FUN Advent Calendar 2016 1日目の記事です。
某ステムプログラミングの課題の途中で感じた違和感について調べてみたという話です。

$whoami

学部3年、@neglect_ypです。
素因数分解をする某プロジェクトに所属しています。

終了ステータスが何か変だぞ…?

以前に作ったオレオレシェルを改造し、シグナルハンドラを用いてCtrl-Cを押した際に実行中のプロセスにSIGINTを送れるようにしようというのが、今回の課題でした。

実装自体はサクッと行い、一見うまくSIGINTを送れているようにも見えたのですが、終了ステータスが0であるという表示が出ており、頭に「?」が浮かびました。SIGINTを送って中断したということは、正常に終了してはいないのだから、終了ステータスが0であるのはおかしいのではないか?という考えです。

とりあえず、検証用にサイズの小さいコードを書いてみました。

結果は変わらず、終了ステータスは0でした。zsh上では終了ステータスが130になることも確認しました。

ここで僕がした勘違いは、「sleepはSIGINTによって終了したときは、終了ステータスが130になるのが正常な動作なんだ!」と思い込んでしまったことです。

そして、「sleepを実行していたプロセスの終了ステータスが格納されている変数から、どうにかして130という値が取り出せるはずだ」という思考になって、結構な時間を費やしてしまいました。

つまりどういうこと?

なんかうまくまとまらなかったので無理やり結論に…

zsh上でsleepに対してSIGINTを送って、echo $?したときに出てくる数字は、zshが勝手に決めています。 勝手にというと語弊があるかもしれませんが、POSIXでは、「シグナルによって終了したプロセスの終了ステータスは128より大きい値」であることが要求されているようです。しかし、具体的な値は定められていません。

そこで、zshbashなどのシェルでは「128+シグナルの番号」という形で終了ステータスを表しているようです。違う実装になっているシェルもあり、以下に詳しく載っています。

したがって130という値は128+2(SIGINT)の計算結果であり、sleepがSIGINTを受け取ったときにexit(130)するわけではありません。

思ったこと

私の主観ですが、本学はWebサービスを作ったりだとか人工知能に興味がある人が多いと思っています。逆に、私が興味を持っている、システムプログラミングやセキュリティの分野はあまり人気がないと感じていて、もっと好きになってほしいなあと思っています。こんな記事でしたが、興味を持っていただけたなら幸いです。

はしがき

課題をやっているときに、誤ってkill(-1, SIGINT)を実行してしまって、楽しかったです。

一応補足として、PIDが1なプロセスはinitで、すべてのプロセスの親です。そして、killの第1引数が負の数の時、プロセスグループを表します。あとはわかりますね…?