つれづれなる日記 @ maoo.jp

退屈な日々をより退屈な文章でだらだらと

目覚めた瞬間つかまえて

関連
http://d.hatena.ne.jp/maoo/20110211/1297446082
関連
http://d.hatena.ne.jp/maoo/20090903/1252001171

 今時のパーソナルコンピューターといえば、ハードウェアにしてもOSにしてもスリープ機能のようなものを実現している場合がほとんどだと思う。つまり、電源をオフにせず電力消費が小さい状態で眠らせるということであって、デスクトップ・タイプよりノートブック・タイプに適した機能であると考えられる。自分も現在、メインで利用しているマシンで*1これを活用したような運用をしている。再起動(リブート/reboot)は週に一度くらいで、iBookさんのころからそんな習慣なのだった。
 さて、主に利用しているそのMacintoshな環境においてであるのだが、スリープ(Sleep)をする寸前あるいは目覚めた(System Wake)*2直後…ことにこの後者において、自分で設定したいろいろな処理を自由に行わせたい(たとえば任意のアプリケーション・ソフトウェアを自動的に実行するなど)とか思うことがよくある。けっこう前からそんなことを考えていて、それを実現するような方法を模索したことが何度もある。しかし、エレガントで便利で簡単な方法というものは、残念なことにとうとう今まで発見できずにいるのだった。
 そして、そういうことをやりたい方々は自分以外にもけっこうおられるようだ。WWWサイトから情報を得るためにいろいろと検索なんかをしていると、そういうことを模索していたり困っていたりする人々もそれなりに発見できる。Windowsな方面においても、OSの標準提供でユーザーが利用できるようなそういう機構はないような気がするのだが*3、ちょっとこれってどうなんだろう。あると便利な機能だと思うので、OSのメーカーさんにはぜひなんとかしていただきたい。
 ところで、ClassicではないMacOSでは、少なくともシステム内部においては目覚めた瞬間にいろいろと処理を行ったりしていて*4、しかしそれはシステム内部としての機構に近いものに思われた。つまり、一般ユーザーがその機構を(イベントの感知やメッセージの受信を行うなりの方法かと想像するが)利用して同様のタイミングで処理を行う方法は提供されていないのかなと、そんなふうに考えている。実際にはそれは誤解かもしれない。ソフトウェア開発者ではない素人の自分が調査した限りでは…ということだ。
 さて、実際にどういう必要があって以上のような仕組みを望んでいるのかというと、スリープから目覚めた瞬間にntpdの再起動をしたかったからなのであった*5。くわしくははなんだか長くなりそうなので明日かそれ以降に書こうと思うが、簡単に書くと、そのタイミングでntpdの再起動をしないとコンピューターの時刻が正確でなくなったり補正に時間がかかったりするもので*6、それがすごく気分的に嫌だからなのだった。なんとしてでも、目覚めたらすぐにそれをすっきり行いたい…と。
 それで、iBookさんの環境ではどう解決していたかというと、自分でデーモン(Daemon)*7みたいなものを製作して、それでちょっとむりやり対応していた。ハードウェアもOSも進化した今時の環境であるならば、こういう問題は初期状態ですでに解決されているかと期待していたのだが、実際に時刻は不正確になりがちだし*8、そして目覚めた瞬間をつかまえる方法は見つからない。というわけで、iBookさんの場合と同様の方法で対応してみることにしたわけだった。
 システムで用意されているきちんとした仕組みを発見できない以上、エレガントでなく洗練されておらず無駄があるような方式で対応するしかないわけで、あまりくわしく書くと恥ずかしいのだが、要するにそのデーモンらしきプログラムでは

  1. 時刻を定期的に確認していく永遠のループの中で
  2. 時刻にジャンプがあったならスリープのあとの目覚めと判定する

というようなことを行う仕組みにしていた。つまりはものすごく単純なものであり、C言語によるソースプログラムの中核は

oldclock = time(NULL);
while (1) {
        nowclock = time(NULL);
        diffsec = (nowclock - oldclock);
        if (diffsec > bordersec) {
                break;
        }
        oldclock = nowclock;
        sleep(CHECKING_INTERVAL_SEC);
}

こんな感じのものだ。通常はずっとぐるぐるループしてくれることになっているが、ジャンプを感知したらここから脱出して決められた処理を行ってからまた戻ってくることになっている。
 このプログラムについては、ファイルI/Oはなく処理もごくごく単純なものだし、しかも実行時間のうちのほとんどはsleep()での待ちであるから、システムへの負荷はほとんど無視していいはずだ*9。あとは実行ファイルにして*10、システム管理者の権限でシステムのブート(boot)と同時に起動しておけばいいのだが、launchd的なマナーに完全に従って実行させるのもいろいろと面倒そうな気がしたので、"/etc/rc.local"に記述して実行させたり*11
 そんなわけで、自分のささやかな不満点の一つは現在とりあえず(むりやりに)解決されているわけだが、考えれば考えるほど実現方式がいかがなものかと自分でも思う。結果としては便利なんだが方法が下品な感じがするというか、技は皆無なので力だけで解決したみたいな感覚があるというか。登場したばかりの"Snow Leopard"(=バージョン10.6)なら、こんな面倒なことをしなくてもいいようになっているのかな? なっているといいなあ。

*1:ハードウェアは"MacBook Pro"であり、OSは"Mac OS X"のバージョン10.5.8(Leopard)である。

*2:正確には「スリープの解除」「スリープを解除した」あるいは「スリープからの復帰」「スリープから復帰させた」と書くべきだろうか。

*3:もっとも、せいぜい"Windows XP"なやつくらいのことしかよくは知らないのだが。少なくともこの部屋で利用できるWindowsなOSはそれだけだ。

*4:自分が知っている一番古い"Mac OS X"はJaguar(=バージョン10.2)だが、その頃からそうだった。それは、"/var/log"の下のログなんかを参照すると動きがよくわかる。

*5:具体的には、"/bin/launchctl stop org.ntp.ntpd"を実行したいということ。ここにstopとあるが、KeepAlive指定のジョブなので即時再起動の意味になるわけだ。

*6:自分と同じような環境なら、たぶんどなたでもそうなると思う。

*7:参考 デーモン (ソフトウェア) - Wikipedia

*8:半日のスリープで2秒とか3秒とかずれている。もっとも、まだ稼働時間が不足していてドリフトファイルの内容が最適化されていないからその影響で…という可能性もちょっとはあるのかもしれないが。

*9:その予想は、実行時に自分で測定した結果とも合致する。

*10:MacOSはバージョン10シリーズになってから、開発環境がOSに無料できっちりとくっついてくるのがとてもすてき。これは賞賛してもいいことだと思う。

*11:この方式でも、きちんと規則通りであってマナー違反ではない。"/System/Library/LaunchDaemons/com.apple.SystemStarter.plist"中の記述により、"/sbin/SystemStarter"経由で"/etc/rc.local"が起動されることは約束されているわけだから。