initプログラム
今日は突然Linux(UNIX系)のマニアックな話です。Linuxはカーネルがブートすると、最初にinitというプログラムを起動します。プロセスIDは1になります。このプログラムから他の全てのプログラムが起動されます。init自体の解説をしようと言うつもりではないので、このくらいにしておきますが、ポイントはLinuxで最初に起動し、ずっと生き続けるプロセスということです。
当社の組み込みLinuxでのアプライアンス製品群は、コンパクトなArmadilloを使っているものが中心で、コンパクトと言っても昔のPC9801とかに比べればはるかに強力でLinuxもかなり快適に動くのですが、やっぱり今時の普通のPCに比べると非力でリソースも少ないのです。特にRAMが少ないので、大きなプロセスを複数起動するとカーネルに殺されてしまいます。oom(Out Of Memory)キラーという仕組みです。大抵はプログラムに問題があり、無駄にメモリーを使いすぎていたり、リークしているなどして肥大化していることが多いのですが、いずれにしても連続稼働しなければならないシステムでは勝手に殺されてしまうのは結構致命的です。
そこで、最悪死んでも自動で再起動する仕組みを入れておこう、ということになるのですが、oomキラーは手当たり次第大きなプロセスから殺していくので、運が悪いと再起動する仕組み自体が殺されることもあります。一番生き残る確立が高いのはinitプロセスなのです。
initプログラムにはいくつかの種類があるのですが、割とよく使われているSystemV系のinitでは、respawnという記述ができ、そうすることによって死んだらinitが自動で再起動してくれます。ただし、自分自身でデーモン化するようなプログラムは監視ができません。フォアグラウンドで動く状態でinittabに記述しなければなりません。
これは便利!というところなのですが、実は結構致命的なのが、タイムゾーンの設定がされない、という点です。initがrcを実行するとその中でタイムゾーンのセットなどが行われるのですが、init自身はタイムゾーン環境変数がセットされないので、initから起動されるプロセスは同様にタイムゾーンがセットされません。
起動用のシェルスクリプトを作ってそこでタイムゾーンを指定してからプログラムを起動すれば良いのですが、それだけのためにシェルスクリプトを個別に準備するのは面倒です。そこで調べてみると、simpleinitだとコンパイルオプションで指定しておけば、/etc/TZからタイムゾーンを読み込むという仕組みがあることがわかりました。
ところが、simpleinitはSystemV系のinitとはかなり動きが違うので、どうするかなぁ、と思っていたのですが、結局SystemV系のinit、もっともArmadilloではbusyboxですが、それに同様の仕組みを入れてしまいました。まあ、こういうことができるのも組み込み製品の強みですね。ソフトウェア製品で、既存の環境にインストールするとなると、標準コマンドを入れ替えるのは抵抗感がありますので。
そんな感じで、少しEthdelayを改良したりしてました。まあ、Ethdelay関連プログラムにリークなどの問題がないことは十分確認しているのですが、HTTPサーバも使ってますし、念には念を入れて、ということで、自動再起動も組み込んでいます。