2006年11月 5日
システム上のユーザのアイドル時間を調べる
デーモンや cron から何か重い処理を走らせたいときに、作業中のユーザに迷惑をかけないよう、システムにログインして作業しているユーザがいるか確認したいときがあります。ここでは、GNU/Linux システムでつかえる方法をいくつか検討してみたいと思います。
ロードアベレージを調べる
ロードアベレージは/proc/loadavg から調べられます。ロードアベレージが 1を超えるような状況では重い処理は走らせないほうがいいでしょう。
この方法の欠点は、システム全体の忙しさはわかっても、ユーザがログインして作業しているかどうかはわからない点にあります。たとえば、ユーザがテキストエディタなどで軽い作業を行っていた場合、ロードアベレージは低い数字になります。
端末のアイドル時間を調べる
w コマンドを実行すると IDLE という欄に各端末のアイドル時間が表示されます。これは /var/run/utmp というファイルからアクティブな端末の一覧を取得して、現在時刻から各端末のデバイスファイルのアクセス時間を引き算することによって求めています。
/var/run/utmp からアクティブな端末の一覧を取得する、というやや面倒な部分の手を抜けば、この処理は次のように Ruby で簡単に書けます。
# 端末デバイスのリストを取得 ttys = Dir.glob("/dev/tty*") + Dir.glob("/dev/pts/*") # 最小のアイドル時間 idle_time = ttys.map {|x| Time.now - File.atime(x) }.min
大量の /dev/tty* ファイルに対して stat が発生しますが、ディスク上のファイルシステムへのアクセスは行われないので、上のように大雑把に処理を行っても性能の点で問題になることはあまりないと思います。
この方法の欠点は、ユーザが端末を使わずに X 上で作業していた場合、ユーザが作業中かどうかどうかわからない点にあります。
Xのアイドル時間を調べる
X11R5の時代には XGetIdleTime() というそのものずばりの関数を提供する XIdle という拡張があったようですが、現在では使えなくなっているようです。代わりに、XScreenSaver という拡張が導入されましたが、いまいち使いにくい代物のようで、 jwz氏によるバグレポートがあります。
このバグレポートの最後のコメントに XScreenSaver 拡張はアイドル時間を調べるためだけにも使えると指摘があります。実際、 gaimというチャットクライアントでは XScreenSaver 拡張を使ってアイドル時間を調べています。idle.c
また、 OpenBSD には XScreenSaver 拡張を用いて、一定のアイドル時間経過後に任意のプログラムを実行するツール xidle が含まれています。
キーボード・マウスのアイドル時間を調べる
PS/2 キーボード・マウスのアイドル時間は /proc/interrupts の次のような行を定期的に監視すれば調べられます。左から2つ目の値が、割り込みの入った回数を表しています。キーボード・マウスに入力がない間は、これらの値に変化はありません。1 はキーボード (IRQ 1)、12はマウス (IRQ 12) です。
1: 124536 IO-APIC-edge i8042 12: 1443140 IO-APIC-edge i8042
カーネルのバージョンによって /proc/interrupts の内容は異なるため、注意が必要です。xscreensaver の driver/timer.c に /proc/interrupts を監視するコードがあります。 この方法の欠点は USBキーボード・マウスを監視できない点です。
一方、root 権限があれば /dev/input/event* を監視してキーボードやマウスの入力を監視するという方法もあります。こちらの方法は USBキーボード・マウスも問題なく扱えます。
この方法は強力ですが、/dev/input/event* はキーロガーを簡単に作れてしまうデバイスなので、取り扱いには注意が必要です。/dev/input/event* を読むサンプルプログラムとしては evtest.c が参考になります。
evdev モジュールが入っていないカーネルでは次のようにモジュールをインストールする必要があります。
% sudo modprobe evdev
まとめ
システム上のユーザのアイドル時間を調べる方法をいくつか検討しました。デスクトップとして使われていないサーバマシンでは「ロードアベレージ」と「端末のアイドル時間を調べる」の方法を組み合わせれば大体なんとかなると思います。共有サーバを喧嘩せずに使うのに役立つテクニックだと思います。