ふと思いついて秒までで表示できる時計を書こうと思いました。
現在時刻取得と、時刻表示とをループさせると CPU を鬼のようにくってしまうため、1秒単位で表示するようにする必要がある。
秒単位で更新すればいいから sleep(1)で良いかというと0.9秒ぐらいは狂う可能性がありあまり嬉しくない。
もう少し正確に合わせるには現在の時間から ms 単位で sleep して、時間になったら表示する必要があります。そして調べてみると usleep(3) というマイクロ秒単位で sleep 出来る関数を発見。試してみたところ、指定した時間以上 sleep するんですが、時間を過ぎても他のプログラムが動いているとすぐに戻ってきてくれません。
そこで man を叩きまくって setitimer(3) という関数を発見。μs 単位でタイマーを指定し、指定時間経過後に SIGALRM を送ってくれます。そして signal(SIGALRM, get_date) と書いておくことで、SIGALRM が来たときに get_date という関数を実行します。SIGALRM(を含めたシグナル)はソフトウェア割り込みという物で、割り込みと言うからには他のプログラムが動いていても割り込んで指定した関数を実行させることができます。多分。
簡単にいうと BASIC の ON INTERVAL=<時間> GOSUB <行番号> っぽいことが出来ます。
で、頑張って書いてみたところ FreeBSD 6.0-STABLE(Pen2@400MHz) では 2,3msの遅れで表示できているが、FreeBSD 5.4-RELEASE(P3@1133MHz)と、FreeBSD 4.11-STABLE(Pen/P54C@133MHz)では、8~20ms 程度遅れて表示されてしまう。
速いマシンでも遅れるというのが良く分からなかったんですが、悩むことしばし。割り込みの周波数がデフォルトでは FreeBSD 5.x までは HZ=100 (1秒間に100回チェック = 10ms) 6.0 では HZ=1000 (1ms)になったのを思い出し4.11 と 5.4 も HZ=1000 を設定し kernel の再構築中...完了。(100ms 毎に更新 / 1000ms毎の更新)
4.11 (Pen/P54C@133): 3ms台 / 6~20ms台(大体 12,3ms)
5.4 (PenII@400): 2ms未満 / 1~2ms台
となりました(4.11 はSSH の向こう側なので多少値が悪いかも)。ntpd で合わせているとはいえ、そんな精度で時計が合っているのだろうか?
「It is strongly recommended to use HZ=1000 or 2000 with DEVICE_POLLING to achieve smoother behaviour.」と書かれているのに HZ=100 で DEVICE_POLLING を使っていたのが裏目に出たか。HZ=2000 って、そんなことやったら P133 なマシンでは割り込み処理ばっかりになってまともなプログラムを実行する時間がなくなってしまうような...
現在時刻取得と、時刻表示とをループさせると CPU を鬼のようにくってしまうため、1秒単位で表示するようにする必要がある。
秒単位で更新すればいいから sleep(1)で良いかというと0.9秒ぐらいは狂う可能性がありあまり嬉しくない。
もう少し正確に合わせるには現在の時間から ms 単位で sleep して、時間になったら表示する必要があります。そして調べてみると usleep(3) というマイクロ秒単位で sleep 出来る関数を発見。試してみたところ、指定した時間以上 sleep するんですが、時間を過ぎても他のプログラムが動いているとすぐに戻ってきてくれません。
そこで man を叩きまくって setitimer(3) という関数を発見。μs 単位でタイマーを指定し、指定時間経過後に SIGALRM を送ってくれます。そして signal(SIGALRM, get_date) と書いておくことで、SIGALRM が来たときに get_date という関数を実行します。SIGALRM(を含めたシグナル)はソフトウェア割り込みという物で、割り込みと言うからには他のプログラムが動いていても割り込んで指定した関数を実行させることができます。多分。
簡単にいうと BASIC の ON INTERVAL=<時間> GOSUB <行番号> っぽいことが出来ます。
で、頑張って書いてみたところ FreeBSD 6.0-STABLE(Pen2@400MHz) では 2,3msの遅れで表示できているが、FreeBSD 5.4-RELEASE(P3@1133MHz)と、FreeBSD 4.11-STABLE(Pen/P54C@133MHz)では、8~20ms 程度遅れて表示されてしまう。
速いマシンでも遅れるというのが良く分からなかったんですが、悩むことしばし。割り込みの周波数がデフォルトでは FreeBSD 5.x までは HZ=100 (1秒間に100回チェック = 10ms) 6.0 では HZ=1000 (1ms)になったのを思い出し4.11 と 5.4 も HZ=1000 を設定し kernel の再構築中...完了。(100ms 毎に更新 / 1000ms毎の更新)
4.11 (Pen/P54C@133): 3ms台 / 6~20ms台(大体 12,3ms)
5.4 (PenII@400): 2ms未満 / 1~2ms台
となりました(4.11 はSSH の向こう側なので多少値が悪いかも)。ntpd で合わせているとはいえ、そんな精度で時計が合っているのだろうか?
「It is strongly recommended to use HZ=1000 or 2000 with DEVICE_POLLING to achieve smoother behaviour.」と書かれているのに HZ=100 で DEVICE_POLLING を使っていたのが裏目に出たか。HZ=2000 って、そんなことやったら P133 なマシンでは割り込み処理ばっかりになってまともなプログラムを実行する時間がなくなってしまうような...